Skip to content

Ruby 运算符

Ruby 提供了一组丰富的运算符,其中许多是方法调用的语法糖。例如,a + b 通常被解释为 a.+(b),这意味着调用对象 a 的 + 方法,并传入 b 作为参数。这允许类为标准运算符定义自定义行为(即运算符重载)。

对于大多数二元算术和位运算符(例如 +, -, *, /, %, **, &, |, ^, <<, >>),都存在相应的缩写赋值运算符(例如 +=, -= 等)。

假设变量 a 的值为 10,变量 b 的值为 20:

运算符描述示例
+加法:对两边的值进行相加。a + b 将得到 30
-减法:从左操作数中减去右操作数。a - b 将得到 -10
*乘法:对两边的值进行相乘。a * b 将得到 200
/除法:用左操作数除以右操作数。如果两者都是整数,则执行整数除法(截断结果)。b / a 将得到 2。10 / 3 得到 3。10.0 / 3 得到 3.333…
%取模:用左操作数除以右操作数,并返回余数。b % a 将得到 0。10 % 3 得到 1。
**指数:将左操作数提升到右操作数的幂。a**2(a 的 2 次方)将得到 100

这些运算符比较两个值并返回 true 或 false。假设 a = 10 且 b = 20:

运算符描述示例
==相等:检查两个操作数的值是否相等。可能会执行类型转换(例如,10 == 10.0 为 true)。(a == b) 为 false。
!=不等:检查两个操作数的值是否不相等。(a != b) 为 true。
>大于:检查左操作数的值是否大于右操作数。(a > b) 为 false。
<小于:检查左操作数的值是否小于右操作数。(a < b) 为 true。
>=大于或等于。(a >= b) 为 false。
<=小于或等于。(a <= b) 为 true。
<=>组合比较(飞船)运算符:如果操作数相等返回 0,如果第一个操作数较大返回 1,如果第一个操作数较小返回 -1。对于排序至关重要。(a <=> b) 返回 -1。(a <=> 10) 返回 0。
===Case 相等(三等号):在 case 语句中隐式使用。其行为因类而异。例如,(1..10) === 5 为 true(检查 5 是否在范围内)。String === "hello" 为 true(检查 “hello” 是否是 String 的实例)。(1...10) === 5 返回 true。
.eql?类型和值相等:如果接收者和参数类型相同且值相等,则返回 true。1 == 1.0 返回 true,但 1.eql?(1.0) 返回 false。
.equal?对象标识:如果接收者和参数指向内存中的同一个对象,则返回 true。如果 x = "hi" 且 y = "hi",那么 x == y 为 true,但 x.equal?(y) 通常为 false(它们是不同的字符串对象)。如果 z = x,那么 x.equal?(z) 为 true。

假设 a = 10 且 b = 20:

运算符描述示例
=简单赋值:将右侧的值赋给左侧操作数。c = a + b 将 a + b 的值赋给 c。
+=加法和赋值:将右操作数加到左操作数,并将结果赋给左操作数。c += a 等同于 c = c + a。
-=减法和赋值。c -= a 等同于 c = c - a。
*=乘法和赋值。c *= a 等同于 c = c * a。
/=除法和赋值。c /= a 等同于 c = c / a。
%=取模和赋值。c %= a 等同于 c = c % a。
**=指数和赋值。c **= a 等同于 c = c ** a。

Ruby 支持在一个语句中为多个变量赋值。这对于同时初始化多个变量或交换值非常有用。

a = 10
b = 20
c = 30

可以写成:

a, b, c = 10, 20, 30

要交换两个变量的值:

x = 5
y = 10
x, y = y, x # 现在 x 是 10, y 是 5

位运算符作用于整数的二进制表示。

假设 a = 60 (二进制 00111100) 且 b = 13 (二进制 00001101):

a = 00111100
b = 00001101
-----------------
a & b = 00001100 (12)
a | b = 00111101 (61)
a ^ b = 00110001 (49)
~a = 11000011 (补码,解释取决于符号和系统)
运算符描述示例 (a=60, b=13)
&按位与:如果位同时存在于两个操作数中,则将该位复制到结果中。(a & b) 将得到 12 (二进制 00001100)。
|按位或:如果位存在于任一操作数中,则复制该位。(a | b) 将得到 61 (二进制 00111101)。
^按位异或:如果位仅设置在一个操作数中,则复制该位。(a ^ b) 将得到 49 (二进制 00110001)。
~按位取反 (NOT):一元运算符,翻转所有位。(~a) 将得到 -61 (对于典型的有符号整数表示,采用 2 的补码)。
<<按位左移:将左操作数的位向左移动右操作数指定的位数。用零填充。a << 2 将得到 240 (二进制 11110000)。
>>按位右移:将左操作数的位向右移动。对于负数(算术移位 vs 逻辑移位)的行为可能取决于实现,但对于正数,用零填充。a >> 2 将得到 15 (二进制 00001111)。

逻辑运算符用于组合条件语句。在 Ruby 中,false 和 nil 被认为是假值 (falsy),而所有其他值(包括 0, [], "")都是真值 (truthy)。

假设 a = true, b = false, x = 10 (真值), y = nil (假值):

运算符描述优先级示例
&&逻辑与:如果两个操作数都是真值,则返回 true。采用短路求值。较高(a && x) 为 true。(b && x) 为 false。
||逻辑或:如果至少一个操作数是真值,则返回 true。采用短路求值。较高(a || b) 为 true。(b || y) 为 false。
!逻辑非 (一元):反转操作数的逻辑状态。最高!a 为 false。!b 为 true。
and逻辑与:类似于 && 但优先级较低。较低(x and a) 为 true。(y and a) 为 nil (返回假值)。
or逻辑或:类似于 || 但优先级较低。较低(x or b) 为 10 (返回第一个真值)。(y or b) 为 false。
not逻辑非:类似于 ! 但优先级较低。较低not a 为 false。not b 为 true。

重要提示:关于优先级 && 和 || 的优先级高于 and 和 or。这个区别至关重要。例如,result = x || y && z 与 result = x or y and z 不同。通常建议使用 && 和 || 进行布尔逻辑运算,使用 and/or 进行控制流(例如,do_something or raise "Error")。使用括号 () 可以明确意图。

三元运算符提供了一种简洁的方式来编写简单的 if-else 语句。语法:条件 ? 条件为真时的表达式 : 条件为假时的表达式。

运算符描述示例
? :条件表达式age = 20; status = (age >= 18 ? "Adult" : "Minor") (status 将是 “Adult”)

范围运算符创建表示值序列的 Range 对象。

运算符描述示例
..包含末尾范围:创建从起点到终点的范围,包含终点。1..5 创建表示 1, 2, 3, 4, 5 的范围。
...不包含末尾范围:创建从起点到终点(但不包含终点)的范围。1...5 创建表示 1, 2, 3, 4 的范围。

defined? 是一个特殊运算符(看起来像方法调用),用于检查给定的表达式(变量、方法等)是否已定义。如果已定义,它返回一个描述表达式类型的字符串;如果未定义,则返回 nil。它对于自省和条件代码执行非常有用。

示例:

foo = 42
defined? foo # => "local-variable" (局部变量)
defined? $global # => "global-variable" (全局变量) (如果 $global 已定义,否则 nil)
defined? bar # => nil (如果 bar 未定义为变量或方法)
defined? puts # => "method" (方法) (如果 puts 是作用域中已定义的方法)
defined? Math::PI # => "constant" (常量) (如果 Math::PI 已定义)
defined? MyClass # => "constant" (常量) (如果 MyClass 是已定义的类)
defined? yield # => "yield" (如果一个 block 被传递给当前方法),否则 nil
defined? super # => "super" (如果当前方法可以调用 super),否则 nil

Ruby 点运算符 (.) 和双冒号运算符 (::)

Section titled “Ruby 点运算符 (.) 和双冒号运算符 (::)”
  • 点运算符 (.): 用于调用对象上的方法。示例:my_string.length, my_array.sort。
  • 双冒号运算符 (::): 作用域解析运算符。用于访问类或模块内定义的常量(包括类和模块本身)。示例:Math::PI, MyModule::MyClass。它也可以用于调用类方法,如果类本身在某些上下文中被视为常量,但更常用的是 ClassName.class_method。

使用 :: 访问常量的示例:

module MyModule
MY_CONSTANT = "Hello from MyModule"
class Helper
HELPER_CONSTANT = "Helper here!"
end
end
puts MyModule::MY_CONSTANT # => Hello from MyModule
puts MyModule::Helper::HELPER_CONSTANT # => Helper here!

下表列出了运算符的优先级,从最高(最先评估)到最低。同一行的运算符通常具有相似的优先级,并根据结合性进行评估(通常是左结合,除了指数和赋值)。

运算符描述结合性
::常量解析左结合
[] []=元素引用,元素设置左结合
**指数运算右结合
! ~ + - (一元)逻辑非,按位非,一元加,一元减右结合
* / %乘法,除法,取模左结合
+ - (二元)加法,减法左结合
>> <<按位右移,按位左移左结合
&按位与左结合
^ |按位异或,按位或左结合
<= < > >=比较运算符左结合 (允许链式比较, 例如 a < b < c)
<=> == === != =~ !~相等,Case 相等,模式匹配运算符左结合 (对于某些如 == 在复杂链中无括号时,无结合性)
&&逻辑与 (高优先级)左结合
||逻辑或 (高优先级)左结合
.. ...范围创建无结合性
? :三元条件右结合
= %= /= -= += |= &= >>= <<= *= &&= ||= **=赋值运算符右结合
defined?检查是否定义N/A
not逻辑非 (低优先级)右结合
or and逻辑或和逻辑与 (低优先级)左结合

**注意:**列表中的许多运算符都是方法,可以被覆盖。在使用运算符时,特别是不确定优先级时,使用括号 () 始终是确保清晰性和强制执行所需操作顺序的好习惯。