ZetCode

Ruby 表达式

最后修改于 2023 年 10 月 18 日

在本 Ruby 教程中,我们将介绍表达式。

表达式由操作数和运算符构成。表达式的运算符指示对操作数应用哪些操作。表达式中运算符的求值顺序由运算符的优先级结合性决定。

运算符是一个特殊的符号,表示要执行某个过程。编程语言中的运算符取自数学。程序员使用数据。运算符用于处理数据。一个操作数是运算符的输入(参数)之一。

Ruby 运算符

下表显示了常见的 Ruby 运算符,按优先级排序(优先级从高到低)

类别 符号
解析、访问运算符 :: .
数组运算符 [ ] [ ]=
求幂 **
非、补码、一元加、减 ! ~ + -
乘、除、取模 * / %
加法、减法 + -
移位运算符 << >>
按位与 &
按位或、逻辑或 ^ |
关系运算符 > >= < <=
按位或、逻辑或 ^ |
相等、模式匹配运算符 <=> == === != =~ !~
逻辑与 &&
逻辑或 ||
范围运算符 .. ...
三元 ?:
赋值运算符 = += -= *= **= /= %= &= |= ^= <<= >>= ||= &&=
备用否定 not
备用逻辑或、与 or and

表格同一行上的运算符具有相同的优先级。

一个运算符通常有一个或两个操作数。那些只处理一个操作数的运算符称为一元运算符。那些处理两个操作数的被称为二元运算符。还有一个三元运算符 ?:,它处理三个操作数。

某些运算符可能用于不同的上下文中。例如 + 运算符。从上表可以看出,它用于不同的情况下。它添加数字,连接字符串,指示数字的符号。我们说运算符被重载

Ruby 符号运算符

有两个符号运算符:+-。它们用于表示或改变值的符号。

sign_operators.rb
#!/usr/bin/ruby

puts +2
puts -2

+ 和 - 符号表示值的符号。加号可用于表示我们有一个正数。它可以省略,并且通常是这样做的。

在下面的示例中,我们使用减号。

minus_oper.rb
#!/usr/bin/ruby

a = 1

puts a
puts -(a)
puts -(-(a))

减号会改变值的符号。

$ ./minus_oper.rb
1
-1
1

Ruby 赋值运算符

赋值运算符 = 将一个值赋给一个变量。变量是值的占位符。在数学中,= 运算符具有不同的含义。在等式中,= 运算符是一个相等运算符。等式的左边等于右边。

x = 1
puts x # prints 1

在这里,我们将一个数字赋给 x 变量。

x = x + 1
puts x # prints 2

前面的表达式在数学上没有意义。但它在编程中是合法的。该表达式将 1 加到 x 变量。右边等于 2,并将 2 赋给 x

3 = x;

此代码示例会导致语法错误。我们不能将值赋给字面量。

Ruby 解析、成员访问运算符

这两个运算符在运算符层次结构中具有最高的优先级。这意味着它们总是先被求值。

resolution.rb
#!/usr/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

我们使用 :: 运算符访问两者的常量。

$ ./resolution.rb
3.1415926535
People

. 运算符是一个成员访问运算符。它用于调用对象的方法。

member_access.rb
#!/usr/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

字符串是一个内置对象,它有一个反转方法。正在调用它。

$ ./member_access.rb
Jane is 17 years old
edoCteZ

Ruby 连接字符串

在 Ruby 中,+ 运算符也用于连接字符串。当运算符在不同的上下文中以不同的方式使用时,我们说它被重载

catstrings.rb
#!/usr/bin/ruby

puts "Return " + "of " + "the " + "King"
puts "Return ".+"of ".+ "the ".+"King"

我们使用字符串连接运算符将三个字符串连接在一起。

puts "Return " + "of " + "the " + "King"

我们使用 + 运算符连接四个字符串。

puts "Return ".+"of ".+ "the ".+"King"

在幕后,+ 运算符是一个 Ruby 方法。字符串字面量是一个对象。我们使用访问 . 运算符调用对象的方法。

$ ./catstrings.rb
Return of the King
Return of the King

这就是我们运行 catstrings.rb 程序时得到的结果。

Ruby 递增、递减运算符

Ruby 没有这样的运算符。

x++;
x = x + 1;
...
y--;
y = y - 1;

这些是 C 中的递增、递减运算符。

如果您熟悉 Java、C、C++,您就会知道这些运算符。它们在 Ruby 中不可用。Python 语言也没有它们。

Ruby 算术运算符

以下是 Ruby 中的算术运算符表。

符号名称
+加法
-减法
*乘法
/除法
%余数
**功率

在下一个示例中,我们使用算术运算。

arithmetic.rb
#!/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

% 运算符称为余数或模运算符。它找到一个数除以另一个数的余数。例如,9 % 4,9 模 4 是 1,因为 4 进入 9 两次,余数为 1。

$ ./arithmetic.rb
33
2
110
4
2
61917364224

接下来,我们展示整数和浮点数除法之间的区别。

division.rb
#!/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

如果其中一个值是浮点数(或两者都是),我们执行浮点除法。浮点值有一个小数点。我们也可以调用 to_f 方法将整数转换为浮点数。

$ ./division.rb
2
2.5
2.5
2.5

在这里我们看到了 division.rb 程序的结果。

Ruby 有其他执行除法的方法。这些可用作方法调用。

division2.rb
#!/usr/bin/ruby

puts 5.div 2.0
puts 5.fdiv 2
puts 5.quo 2
puts 5.0.quo 2.0

在上面的例子中,我们有 divfdivquo 方法。

puts 5.div 2.0

div 方法总是执行整数除法。即使操作数是浮点值。

puts 5.fdiv 2

fdiv 方法总是执行浮点除法。

puts 5.quo 2
puts 5.0.quo 2.0

quo 方法执行最精确的除法。如果任何操作数是浮点数,则返回一个浮点数,否则返回有理数。

$ ./division2.rb
2
2.5
5/2
2.5

Ruby 布尔运算符

在 Ruby 中,我们有以下逻辑运算符。布尔运算符也称为逻辑运算符。

符号名称
&&逻辑与
||逻辑或
!逻辑非

布尔运算符处理真值。Ruby 有额外的备用布尔运算符。它们是 andor & not。它们做同样的事情,除了它们具有较低的优先级。这种重复来自 Perl 语言,Perl 语言需要具有较低优先级的布尔运算符。

boolean_operators.rb
#!/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 语句的主体。表达式 x > y 返回 true,因此消息“y is greater than x”将打印到终端。

下一个示例显示了逻辑 and 运算符。

and_operator.rb
#!/usr/bin/ruby

puts true && true
puts true && false
puts false && true
puts false && false

只有当两个操作数都为真时,and 运算符才计算为真。

$ ./and_operator.rb
true
false
false
false

只有一个表达式的结果是真。

如果任何一个操作数为真,则逻辑或 || 运算符的计算结果为真。

or_operator.rb
#!/usr/bin/ruby

puts true || true
puts true || false
puts false || true
puts false || false

如果运算符的任一边为 true,则操作的结果为 true。

$ ./or_operator.rb
true
true
true
false

三个表达式的结果为布尔真。

否定 ! 使真为假,假为真。

negation.rb
#!/usr/bin/ruby

puts !0
puts !1
puts !true
puts !false

puts ! (4<3)
puts ! "Ruby".include?("a")

该示例展示了否定运算符的实际应用。

$ ./negation.rb
false
false
false
true
true
true

||&& 运算符是短路求值的。短路求值意味着仅当第一个参数不足以确定表达式的值时,才会对第二个参数进行求值:当逻辑与的第一个参数求值为假时,整体值必须为假;并且当逻辑或的第一个参数求值为真时,整体值必须为真。短路求值主要用于提高性能。

一个例子可以更清楚地说明这一点。

short_circuit.rb
#!/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。短路 && 不计算第二种方法。没有必要。一旦一个操作数为假,逻辑结论的结果就总是假。只有“Inside one”打印到控制台。

puts "##############################"

if two || one
    puts "Pass"
end

在第二种情况下,我们使用 || 运算符并将两种方法用作第一个操作数。在这种情况下,将“Inside two”和“Pass”字符串打印到终端。再次没有必要对第二个操作数求值,因为一旦第一个操作数求值为真,逻辑或就总是真。

$ ./short_circuit.rb
Short circuit
Inside one
##############################
Inside two
Pass

我们看到了 shortcircuit.rb 程序的结果。

Ruby 关系运算符

关系运算符用于比较值。这些运算符始终产生布尔值。

符号含义
<小于
<=小于或等于
> 大于
>=大于或等于

关系运算符也称为比较运算符。

relational.rb
#!/usr/bin/ruby

p 3 < 4
p 3 > 5
p 3 >= 3

表达式 3 < 4 返回 true,因为 3 小于 4。表达式 3 > 5 返回 false,因为它不是真的 3 大于 5。

Ruby 按位运算符

十进制数对人类来说是自然的。二进制数对计算机是原生的。二进制、八进制、十进制或十六进制符号只是相同数字的表示法。按位运算符处理二进制数的位。

符号含义
~按位取反
^按位异或
&按位与
|按位或
<<左移
>>右移

按位运算符很少用于像 Ruby 这样的高级语言中。

bitwise.rb
#!/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 时,结果的该位为 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

按位移位运算符将位向右或向左移动。这些运算符也称为算术移位。

Ruby 复合赋值运算符

复合赋值运算符由两个运算符组成。它们是简写运算符。

compound.rb
#!/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

这两行做同样的事情;它们将 1 加到 a 变量。

其他复合运算符是

-=   *=  **=  /=   %=   &=   |=   <<=   >>=

Ruby 运算符优先级

运算符优先级告诉我们哪些运算符首先被求值。优先级级别对于避免表达式中的歧义是必需的。

以下表达式的结果是 28 还是 40?

3 + 5 * 5

就像在数学中一样,乘法运算符的优先级高于加法运算符。所以结果是 28。

(3 + 5) * 5

要更改求值顺序,我们可以使用括号。括号内的表达式始终首先被求值。

precedence.rb
#!/usr/bin/ruby

puts 3 + 5 * 5
puts (3 + 5) * 5

puts ! true | true
puts ! (true | true)

在此代码示例中,我们展示了一些常见的表达式。每个表达式的结果都取决于优先级级别。

puts 3 + 5 * 5

这行打印 28。乘法运算符的优先级高于加法。首先计算 5*5 的乘积。然后加上 3。

puts ! true | true

在这种情况下,否定运算符具有更高的优先级。首先,第一个真值被否定为假,然后 | 运算符将假和真结合起来,最终得到真。

$ ./precedence.rb
28
40
true
false

Ruby 结合性

有时,优先级不足以确定表达式的结果。还有另一条规则称为结合性。运算符的结合性决定了具有相同优先级级别的运算符的求值顺序。

9 / 3 * 3

此表达式的结果是什么,9 还是 1?乘法、除法和模运算符都是从左到右关联的。因此,表达式的求值方式如下:(9 / 3) * 3,结果为 9。

算术、布尔、关系和按位运算符都具有从左到右的结合性。

另一方面,赋值运算符是右结合的。

a = b = c = d = 0
print a, b, c, d # prints 0000

如果结合律是从左到右,那么前面的表达式将无法实现。

复合赋值运算符是右到左结合的。

j = 0
j *= 3 + 1
puts j

您可能期望结果是 1。但实际结果是 0,因为结合性。右侧的表达式首先被求值,然后应用复合赋值运算符。

Ruby 范围运算符

Ruby 有两个范围运算符。它们用于快速创建对象的范围。最常见的是数字或字母的范围。

.. 范围运算符(两个点)创建包含范围。... 运算符(三个点)创建一个排除范围,其中范围的高值被排除。

range_operator.rb
#!/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_operator.rb
[1, 2, 3]
[1, 2]
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]

Ruby 三元运算符

三元运算符 ?: 是一个条件运算符。 对于我们想要根据条件表达式选择两个值之一的情况,它是一个方便的运算符。

cond-exp ? exp1 : exp2

如果 cond-exp 为 true,则评估 exp1 并返回结果。 如果 cond-exp 为 false,则评估 exp2 并返回其结果。

ternary.rb
#!/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

首先,求值赋值运算符右侧的表达式。三元运算符的第一阶段是条件表达式求值。因此,如果年龄大于或等于 18,则返回 ? 字符之后的值。如果没有,则返回 : 字符之后的值。然后将返回的值分配给 adult 变量。

$ ./ternary.rb
Adult

一个 32 岁的人是成年人。

计算质数

我们将计算素数。

primes.rb
#!/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

在上面的例子中,我们处理了几个运算符。素数(或素数)是一个自然数,它恰好有两个不同的自然数除数:1 和它本身。我们取一个数字,然后用数字除以它,从 2 到取出的数字。实际上,我们不必尝试所有较小的数字,我们可以除以小于所选数字的平方根的数字。该公式将起作用。该算法的核心是余数除法运算符,也称为模运算符。

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

如果只用小于一个数平方根的数字进行模除,我们就可以。如果余数除法运算符对任何 i 值返回 0,则所讨论的数字不是素数。

print i, " " unless not_prime

如果未设置 not_prime 标志,则打印该数字。

上面的示例旨在演示几个运算符。实际上,有一种更容易的方法来计算素数。Ruby 有一个用于计算素数的模块。

primes2.rb
#!/usr/bin/ruby

require 'prime'

Prime.each(50) do |i|
    print i, " "
end

puts

一个示例,使用 Ruby 素数模块计算最大为 50 的素数。

require 'prime'

我们包含素数模块。

Prime.each(50) do |i|
    print i, " "
end

我们计算最大为上限 — 50 的素数。

$ ./primes2.rb
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

从这个输出中,我们可以看到 2 和 50 之间的素数。

在本 Ruby 教程中,我们介绍了表达式。