POSTS
第八章、ruby中的表达式
表达式
在这章的教程将介绍Ruby的表达式。
表达式是由操作数和操作符构成的。表达式的操作符表明了对操作数应用什么操作。表达式中操作符的求值顺序由操作符的优先级和结合律决定的。
操作符是一个特殊的符号表明了要执行的确切操作。编程语言中的操作符取自数学运算。程序员使用数据,操作符用于处理数据。操作数是操作符的参数。
以下表格中按优先级展示Ruby的操作符(高优先级在前):
分类 | 符号 |
---|---|
解析,访问操作符 | :: . |
数组操作符 | [] []= |
求幂 | ** |
非,反,一元加、减 | ! ~ + - |
乘、除、模 | * / % |
加、减 | + - |
移位 | << >> |
位与 | & |
位或、逻辑或 | ^ | |
关系运算 | > >= < <= |
相等、模式匹配 | <=> == === != =~ !~ |
逻辑与 | && |
逻辑或 | || |
范围操作符 | .. … |
三目运算 | ?: |
分配操作 | = += -= *= **= /= %= &= |= ^= <<= >>= ||= &&= |
否定 | not |
逻辑或、与 | or and |
同一行的操作符具有相同的优先级。
一个操作符通常有两个操作数。那些只有一个操作数的操作符称为一元操作符。有两个操作数的称为二元操作符。有一个三元操作符(?:)有三个操作数。
操作符可能用于不同的上下文。例如+操作符,从上面的表格可知它能用于不同情况。数字求和、连接字符串、作为数字的符号。我们称这个操作符被重载了。
正负号操作数
有两个正负号操作符,+和-,用于指定或者修改值的符号。
puts +2
puts -2
+和-指明了值的符号。加号表明是正数,通常可省略。
接下来的例子我们使用减号。
#!/usr/bin/ruby
a = 1
puts a
puts -(a)
puts -(-(a))
减号改变了值的符号。
$ ./sign.rb
1
-1
1
分配操作数
分配操作符=将一个值分配给一个变量。变量是这个值的点位符。数学运算中=操作符有不同的意义。在方程式中=是相等操作,左边的值等于右边的值。
x = 1
puts x # prints 1
这里分配的一个数字给*x*变量。
x = x + 1
puts x # prints 2
前一个表达式中数学运算中是行不通的。但是在程序中是合法的。这个表达式是将x变量加1,右边等于2,并把2赋值给x。
3 = x;
这个语法是错误的,我们不能组值分配字面符。
解析,成员访问操作符
有两个操作符具有最高的优先级,这意味着它们总是先求解。
#!/usr/local/rvm/rubies/ruby-2.3.0/bin/ruby
class MyMath
Pi = 3.1415926535
end
module People
Name = "People"
end
puts MyMath::Pi
puts People::Name
第一个例子展示了::命名空间解析操作符。它可以访问一个定义在其它类或模块里的常量、模块或者类。它用于提供命名空间,这样方法和类的名字就不会与其他作者的类冲突了。
class MyMath
Pi = 3.1415926535
end
module People
Name = "People"
end
这里创建了一个模块和一个类,分别定义了一个常量。
puts MyMath::Pi
puts People::Name
我们使用::操作符访问它们的常量。
➜ ~ ruby resolution.rb
3.1415926535
People
点(.)操作符是成员访问,用于调用对象的方法。
#!/usr/local/rvm/rubies/ruby-2.3.0/bin/ruby
class Person
def initialize name, age
@name = name
@age = age
end
def info
"#{@name} is #{@age} years old"
end
end
p = Person.new "Jane", 17
puts p.info
puts "ZetCode".reverse
这个例子中我们创建了两个对象,一个是用户定义的,一个是预定义的。我们对这些对象使用点操作符。
p = Person.new "Jane", 17
puts p.info
在这行使用点操作符调用了两个方法:new和info。
puts "ZetCode".reverse
字符串是内建对象,具有一个reverse方法。
➜ ~ ruby memberaccess.rb
Jane is 17 years old
edoCteZ
字符串连接
Ruby中+操作符同样可以用于字符串连接。在不同上下文中操作符作用不同,我们称这个为重载。
#!/usr/local/rvm/rubies/ruby-2.3.0/bin/ruby
puts "Return " + "of " + "the " + "King"
puts "Return ".+"of ".+ "the ".+"King"
我们将三个字符串连接在一起。
puts "Return " + "of " + "the " + "King"
我们使用+操作符连接字符串。
puts "Return ".+"of ".+ "the ".+"King"
+操作符也是Ruby的一个方法。我们可以使用访问操作符(.)来调用它。
➜ ~ ruby catstrings.rb
Return of the King
Return of the King
增、减操作符
Ruby中没有如下操作。 x++; … y–;
这些是C语言的增、减操作。
如果你熟悉Java、C、C++,你可能了解这些操作符。但是这些在Ruby中无效的。同样在Python中也没有。
算数操作符
下面的表格是Ruby中的算术操作符。
符号 | 名字 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 模 |
** | 幂 |
下面的例子中我们使用了算术操作符。
#!/usr/bin/ruby
a = 10
b = 11
c = 12
puts a + b + c
puts c - a
puts a * b
puts c / 3
puts c % a
puts c ** a
在前面的例子我们使用了加、减、乘、除和取余操作。这些与数学上的是相同的。
puts c % a
%操作符是取余或者求模。
$ ./arithmetic.rb
33
2
110
4
2
61917364224
输出结果。
接下来展示整数和浮点数除法的区别。
#!/usr/bin/ruby
puts 5 / 2
puts 5 / 2.0
puts 5.0 / 2
puts 5.to_f / 2
上面的例子我们将两个数相除。
puts 5 / 2
这个表达式中的操作数都是整数,我们进行的是整数相除。结果返回的也是整数。
puts 5 / 2.0
puts 5.0 / 2
puts 5.to_f / 2
如果其中一个或两个是浮点数,我们进行的是浮点数相除。
$ ./division.rb
2
2.5
2.5
2.5
Ruby有其他方式进行除运算。这些都是有效的方法调用。
#!/usr/bin/ruby
puts 5.div 2.0
puts 5.fdiv 2
puts 5.quo 2
puts 5.0.quo 2.0
上面例子中我们使用了div、fdiv和quo方法。
puts 5.div 2.0
div总是进行整数除,即使操作数是浮点数。
puts 5.fdiv 2
fdiv总是进行浮点数除法。
puts 5.quo 2
puts 5.0.quo 2.0
quo方法进行精确的除法。如果操作数是浮点数则返回浮点数,否则是有理数。
$ ./otherdivision.rb
2
2.5
5/2
2.5
布尔操作符
Ruby中有以下布尔操作符。
符号 | 名字 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 否 |
布尔操作符处理真假值。Ruby中有额外的布尔操作符,and、or、&、not。它们操作是相同的,只是优先级低一些。与Perl语言不同,这需要一个低优先级的布尔操作符。
#!/usr/bin/ruby
x = 3
y = 8
puts x == y
puts y > x
if y > x then
puts "y is greater than x"
end
许多表达式的结果都是一个布尔值。布尔值用于条件语句。
puts x == y
puts y > x
返回布尔值的相关操作符。这两行打印为false和true。
if y > x then
puts "y is greater than x"
end
仅当月if条件为真时if里的语句才会执行。x > y返回true,因此”y is greater than x”会在终端上打印。
下面的例子展示逻辑与操作符。
#!/usr/bin/ruby
puts true && true
puts true && false
puts false && true
puts false && false
与操作只有在操作数都为true才返回true。
$ ./andoperator.rb
true
false
false
false
只有一个表达式的结果为true。
逻辑或操作符当有一个操作数为true则返回true。
#!/usr/bin/ruby
puts true || true
puts true || false
puts false || true
puts false || false
如果有一边是true,操作的结果就是true。
$ ./oroperator.rb
true
true
true
false
三个表达式结果为true。
#!/usr/bin/ruby
puts !0
puts !1
puts !true
puts !false
puts ! (4<3)
puts ! "Ruby".include?("a")
这个例子展示了非操作符的用法。
$ ./not.rb
false
false
false
true
true
true
||和&&操作符是短路求值(short circuit evaluated)。短路求值意味着只有在第一个参数不足以确定表达式的值时第二个参数才会进行求值。短求值主要用于提高执行效率。
用一个例子解释。
#!/usr/bin/ruby
def one
puts "Inside one"
false
end
def two
puts "Inside two"
true
end
puts "Short circuit"
if one && two
puts "Pass"
end
puts "##############################"
if two || one
puts "Pass"
end
在例子中定义了两个方法,用于在布尔操作中作为操作数。我们将看到它们是否被调用了。
if one && two
puts "Pass"
end
第一个方法返回false,短路求值不会计算第二个方法。一旦一个操作数是false,那么这个逻辑的结果总是false。
puts "##############################"
if two || one
puts "Pass"
end
第二种情况我们使用||操作符,并且第一个操作数为two方法。这里同样没有必要对第二个操作数求值,只要第一个操作数为true,那么逻辑或总是为true。
$ ./shortcircuit.rb
Short circuit
Inside one
##############################
Inside two
Pass
shortcircuit.rb程序的运行结果。
关系操作符
关系操作符用于值的比较,其总是返回布尔值。
符号 | 含义 |
---|---|
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
关系操作符又称为比较操作符。
#!/usr/bin/ruby
p 3 < 4
p 3 > 5
p 3 >= 3
表达式3 < 4返回true,因为3小于4。表达式3 > 5返回false,因为3不大于5。
位操作符
人类用的是十进制数字,计算机原生的是二进制数。二进制、八进制、十进制和十六进制只是数字的符号。位操作符针对的是二进制数。
符号 | 含义 |
---|---|
~ | 按位取反 |
^ | 按位异或 |
& | 按位与 |
| | 按位与或 |
<< | 左移位 |
>> | 右移位 |
位操作在高级语言中很少使用。
#!/usr/bin/ruby
puts ~ 7 # prints -8
puts ~ -8 # prints 7
puts 6 & 3 # prints 2
puts 3 & 6 # prints 2
puts 6 ^ 3 # prints 5
puts 3 ^ 6 # prints 5
puts 6 | 3 # prints 7
puts 3 | 6 # prints 7
puts 6 << 1 # prints 12
puts 1 << 6 # prints 64
puts 6 >> 1 # prints 3
puts 1 >> 6 # prints 0
上面的例子中展示了这6个位操作符。
puts ~ 7 # prints -8
puts ~ -8 # prints 7
按位取反是将1变为0,0变为1。将操作会将数字7所有的位都反转,同样包括符号位。如果再次反转所有的位即会得到数字7。
puts 6 & 3 # prints 2
puts 3 & 6 # prints 2
按位与是将两个数进行逐位与操作,只有两个数对应位的都为1结果才为1。
puts 6 ^ 3 # prints 5
puts 3 ^ 6 # prints 5
按位异或是将两个数进行逐位异或操作,只要其中一个数(但不是全部)对应位的为1结果就为1。
puts 6 | 3 # prints 7
puts 3 | 6 # prints 7
按位或是将两个数进行逐位或操作,只要其中一个数对应位的为1结果就为1。
puts 6 << 1 # prints 12
puts 1 << 6 # prints 64
puts 6 >> 1 # prints 3
puts 1 >> 6 # prints 0
移位操作符是按位进行右移或左移,也称为算术移位。
复合分配操作符
复合分配操作符是由两个操作符构成。它们是简写操作符。
#!/usr/bin/ruby
a = 0
a = a + 1
a += 1
puts a
b = 0
b = b - 8
b -= 8
puts b
+=和-=操作符是一个简写的操作符。它们的可读性没有全写的好,但是有经验的程序员经常使用它们。
a = a + 1
a += 1
这两行的操作是一样的,都是将变量a加1。
其他的一些复合操作符。
-= *= **= /= %= &= |= <<= >>=
操作符优先级
操作符的优先级表明了先对哪个操作符进行求值。优先级避免了表达式的二义性。
这个表达式的结果是多少?28还是40?
3 + 5 * 5
跟数学相同,乘法优先级高于加法,加些结果为28。
(3 + 5) * 5
我们可以使用括号来改变优先级。括号里的表达式总是最先求值。
#!/usr/bin/ruby
puts 3 + 5 * 5
puts (3 + 5) * 5
puts ! true | true
puts ! (true | true)
这个例子展示了一些表达式,其结果依赖于操作符优先级。
puts 3 + 5 * 5
这行打印28,因为乘法操作优先级高于加法。
puts ! true | true
这里非操作优先级更高。最后返回为true。
$ ./precedence.rb
28
40
true
false
结合律
有时优先级不能决定表达式的结果。还有另一条规则称为结合律。它决定相同优先级的求值顺序。
9 / 3 * 3
这个的结果是多少?9还是1?乘、除和取模操作是从左到右结合的。因此结果为9。
数学运算、布尔、关系和位操作都是从左向右结合的。
另外赋值操作是右结合。
a = b = c = d = 0
print a, b, c, d # prints 0000
复合分配操作是从右向左结合的。
j = 0
j *= 3 + 1
puts j
你可能期望结果为1,但是实际上结果为0。由于结合律,右边表达式先求值再应用复合分配操作。
范围操作符
Ruby有两个范围操作符,用于创建一个范围对象。通常是数字或者字母的范围。
..范围操作符(两个点)创建一个包含的范围。…操作符(三个点)创建一个非包含的范围,较大的值不包含在其中。
#!/usr/bin/ruby
p (1..3).to_a
p (1...3).to_a
p ('a' .. 'l').to_a
这个例子中我们使用范围操作符创建了数字范围和字母范围。
p (1..3).to_a
p (1...3).to_a
这两行都是使用范围操作符创建了两个范围,然后转换为数据。第一个范围的值为1,2,3;第二个为1和2.
p ('a' .. 'l').to_a
这里使用*..*操作符创建一个’a’到’l’的数组。
$ ./range.rb
[1, 2, 3]
[1, 2]
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
三元运算符
三元运算符是一个条件操作。如果我们需要根据条件表达式从两个值选择一个时这是一个方便的操作。
cond-exp ? exp1 : exp2
如果cond-exp为真则返回exp1,否则返回exp2。
#!/usr/bin/ruby
age = 32
adult = age >= 18 ? true : false
if adult then
puts "Adult"
else
puts "Not adult"
end
许多国家成年是基于你的年龄。是否成年即为是否超过了一定年龄。这种情况适合于三元操作。
adult = age >= 18 ? true : false
首先对赋值符右转进行求值,它的值将赋给adult变量。
$ ./ternary.rb
Adult
32岁已经成年了。
计算素数
我们将计算素数。
#!/usr/bin/ruby
nums = (4..50).to_a
puts "Prime numbers:"
print "2 3 "
nums.each do |i|
not_prime = false
(2..Math.sqrt(i).ceil).each do |j|
not_prime = true if i % j == 0
end
print i, " " unless not_prime
end
puts
上面的例子中我们用到了一些操作符。
nums = (4..50).to_a
我们将从这些数中计算哪些是素数。
print "2 3 "
我们路过2和3,因为它们都是素数。
not_prime = false
not_prime标志表明选择的数不是素数。我们假设选择的数是素数,直到被证明不是为止。
(2..Math.sqrt(i).ceil).each do |j|
not_prime = true if i % j == 0
end
当取模的结果为0表示这个数不是素数。
print i, " " unless not_prime
如果not_prime标志没有设置则打印这个数。
上面例子展示了一些操作符。实际上有更简单方法计算素数。Ruby中有一个计算素数的模块。
#!/usr/bin/ruby
require 'prime'
Prime.each(50) do |i|
print i, " "
end
puts
使用Ruby的prime模块计算素数。
require 'prime'
导入prime模块。
Prime.each(50) do |i|
print i, " "
end
计算到50的素数。
$ ./primes.rb
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
结果输出了2到50之间的素数。
这章的教程介绍了表达式。zetcode原文地址