Ruby 编程/语法/运算符
运算符 | 名称/含义 | 参数 | 优先级[1] | 关联 |
---|---|---|---|---|
! | 布尔非 | 一元 | 1 | 右 |
~ | 按位取反 | 一元 | 1 | 右 |
+ | 一元加(无效果) | 一元 | 1 | 右 |
** | 求幂 | 二元 | 1 | 右 |
- | 一元减(反转符号) | 一元 | 2 | 右 |
* | 乘法 | 二元 | 3 | 左 |
/ | 除法 | 二元 | 3 | 左 |
% | 取模(余数) | 二元 | 3 | 左 |
+ | 加法或连接 | 二元 | 4 | 左 |
- | 减法 | 二元 | 4 | 左 |
<< | 按位左移或追加(<< 和 <<- 也用于 "here doc" 符号) | 二元 | 5 | 左 |
>> | 按位右移 | 二元 | 5 | 左 |
& | 按位与 | 二元 | 6 | 左 |
| | 按位或 | 二元 | 7 | 左 |
^ | 按位异或 | 二元 | 7 | 左 |
< | 小于 | 二元 | 8 | 左 |
<= | 小于或等于 | 二元 | 8 | 左 |
> | 大于 | 二元 | 8 | 左 |
>= | 大于或等于 | 二元 | 8 | 左 |
== | 等于(计算为相同的值) | 二元 | 9 | N/A |
=== | "案例相等"、"案例包含" 或 "三个等号" 运算符。A === B 如果 B 是 A 集合的成员。操作根据 A 和 B 的数据类型而有很大差异。 |
二元 | 9 | N/A |
!= | 不等于 | 二元 | 9 | N/A |
=~ | 模式匹配 | 二元 | 9 | N/A |
!~ | 否定模式匹配 | 二元 | 9 | N/A |
<=> | A <=> B 计算为 -1、0 或 1;如果 A 分别小于、等于或大于 B | 二元 | 9 | N/A |
&& | 布尔与 | 二元 | 10 | 左 |
|| | 布尔或 | 二元 | 11 | 左 |
.. | 范围创建,布尔触发器 | 二元 | 12 | N/A |
... | 开放式范围创建,布尔触发器 | 二元 | 12 | N/A |
?: | A?B:C 如果 A 为真,则计算为 B,否则计算为 C | 三元 | 13 | 右 |
救援 | 用于捕获异常的修饰符,例如 array[3] rescue nil |
二元 | 14 | 左 |
= | 赋值 | 二元 | 15 | 右 |
**= | A **=B 做 A = A ** B | 二元 | 15 | 右 |
*= | A *=B 做 A = A * B | 二元 | 15 | 右 |
/= | A /=B 做 A = A / B | 二元 | 15 | 右 |
%= | A %=B 做 A = A % B | 二元 | 15 | 右 |
+= | A +=B 做 A = A + B | 二元 | 15 | 右 |
-= | A -=B 做 A = A – B | 二元 | 15 | 右 |
<<= | A <<=B 做 A = A << B | 二元 | 15 | 右 |
>>= | A >>=B 做 A = A >> B | 二元 | 15 | 右 |
&&= | A &&=B 如果 A 为真或不为 nil,则将 B 赋值给 A | 二元 | 15 | 右 |
&= | A &=B 做 A = A & B | 二元 | 15 | 右 |
||= | A ||=B 如果 A 为 nil 或假,则将 B 赋值给 A | 二元 | 15 | 右 |
|= | A |= B 做 A = A | B | 二元 | 15 | 右 |
^= | A ^=B 做 A = A ^ B | 二元 | 15 | 右 |
defined? | 如果表达式无法计算(例如未设置的变量),则为 nil | 一元 | 16 | N/A |
not | 布尔非 | 一元 | 17 | 右 |
and | 布尔与 | 二元 | 18 | 左 |
or | 布尔或 | 二元 | 18 | 左 |
if | 条件,例如 print x if x |
二元 | 19 | N/A |
unless | 否定条件,例如 x = 0 unless x |
二元 | 19 | N/A |
while | 循环条件,例如 print x += 1 while (x < 10) |
二元 | 19 | N/A |
until | 循环条件,例如 print x += 1 until (x == 10) |
二元 | 19 | N/A |
优先级较高的(在上面的表格中数字较小的)运算符首先对其直接参数进行计算。优先级顺序可以通过 () 块进行更改。例如,因为 *
的优先级高于 +,那么
1 + 2 * 3 == 7
(1 + 2) * 3 == 9
关联方向控制在同一行中出现多个具有相同优先级的运算符时,哪些运算符首先对其参数进行计算。例如,因为 -
具有左关联
1 – 2 – 3 == (1 – 2) – 3 == -1 – 3 == -4
而不是
1 – 2 – 3 == 1 – (2 – 3) == 1 - -1 == 0
因为 **
具有右关联
2 ** 3 ** 2 == 2 ** (3 ** 2) == 2 ** 9 == 512
而不是
2 ** 3 ** 2 == (2 ** 3) ** 2 == 8 ** 2 == 64
{} 块的优先级低于上述运算符,其次是 do/end 块。使用 [] 的数组访问可以认为具有高于任何上述运算符的优先级。
运算符 ** 到 !~ 可以被重写(为新类定义,或为现有操作重新定义)。
请注意,rescue、if、unless、while 和 until 在用作单行中的修饰符时(如上面的示例)是运算符,但也可以用作关键字。
点运算符 .
用于在对象上调用方法,也称为向对象发送消息。
Ruby 2.3.0 引入了安全导航运算符 &.
,也称为 "孤独运算符"。[2] 这允许替换
x = foo && foo.bar && foo.bar.baz
与
x = foo&.bar&.baz
为哈希和数组引入了等效的 .dig()
方法
hash_variable.dig(:foo, :bar, :baz)
array_variable.dig(1, 0, 2)
是更安全的版本
hash_variable[:foo][:bar][:baz]
array_variable[1][0][2]
安全导航运算符如果请求的方法、键或索引不可用,将引发错误;与使用 try() 来实现此目的不同,后者将返回 nil。[3]
松本行弘在确定使用 &.
之前考虑了 !
?.
和 .?
,因为:[4]
- ?. 与 *? 冲突
- ?. 被其他语言使用,因此 .? 令人困惑地相似但不同
- ! 与 "非" 逻辑冲突
- ? 已经按照惯例用于返回布尔值的函数
- &. 使人联想到正在替换的 && 语法
!!
有时会被看到,但这只是 !
运算符两次。它用于强制以下表达式计算为布尔值。这种技术被认为是非惯用的,并且编程实践不佳,因为存在更明确的方法来强制这种转换(而这种转换很少需要)。
Ruby 中的赋值使用等号 "=" 完成。这既适用于变量也适用于对象,但由于字符串、浮点数和整数实际上是 Ruby 中的对象,因此您始终在分配对象。
示例
myvar = 'myvar is now this string'
var = 321
dbconn = Mysql::new('localhost','root','password')
自我赋值
x = 1 #=>1
x += x #=>2
x -= x #=>0
x += 4 #=>x was 0 so x= + 4 # x is positive 4
x *= x #=>16
x **= x #=>18446744073709551616 # Raise to the power
x /= x #=>1
来自 C 和 C++ 类型的人经常问的一个问题是 "如何递增变量?++ 和 -- 运算符在哪里?" 在 Ruby 中,应该使用 x+=1 和 x-=1 来递增或递减变量。
x = 'a'
x.succ! #=>"b" : succ! method is defined for String, but not for Integer types
多重赋值
示例
var1, var2, var3 = 10, 20, 30
var1 #=> 10
var2 #=> 20
var3 #=> 30
myArray=%w(John Michel Fran Doug) # %w() can be used as syntactic sugar to simplify array creation
var1,var2,var3,var4=*myArray
puts var1 #=>John
puts var4 #=>Doug
names,school=myArray,'St. Whatever'
names #=>["John", "Michel", "Fran", "Doug"]
school #=>"St. Whatever"
条件赋值
x = find_something() #=>nil
x ||= "default" #=>"default" : value of x will be replaced with "default", but only if x is nil or false
x ||= "other" #=>"default" : value of x is not replaced if it already is other than nil or false
运算符 ||= 是一种简写形式,它与表达式非常相似:[5]
x = x || "default"
运算符 ||= 可以是类似于以下代码的简写
x = "(some fallback value)" unless respond_to? :x or x
以同样的方式 &&= 运算符起作用
x = get_node() #=>nil
x &&= x.next_node #=> nil : x will be set to x.next_node, but only if x is NOT nil or false
x = get_node() #=>Some Node
x &&= x.next_node #=>Next Node
运算符 &&= 是表达式的简写形式
x && x = x.get_node()
在 Ruby 中,存在局部作用域、全局作用域、实例作用域和类作用域。
示例
var = 2 4.times do |x| puts x = x*var end #=> 0 2 4 6 puts x #=> undefined local variable or method `x' for main:Object (NameError)
此错误出现是因为此 x(顶层) 不是 do..end 块内的 x(局部),x(局部) 是块的局部变量,而在尝试 puts x(顶层) 时,我们调用的是顶层作用域中的 x 变量,由于不存在,Ruby 就会报错。
$global = 0 4.times do |var| $global = $global + var puts "var #{var} global #{$global}" end #=> var 0 global 0 var 1 global 1 var 2 global 3 var 3 global 6 puts $global #=> 6
此输出给出是因为在变量前面加上美元符号会使变量成为全局变量。
在类的函数内部,可以通过在变量前面加上 @ 来共享变量。
class A def setup @instvar = 1 end def go @instvar = @instvar*2 puts @instvar end end instance = A.new instance.setup instance.go #=> 2 instance.go #=> 4
类变量类似于 Java 中的 "静态" 变量。它由类的所有实例共享。
class A @@classvar = 1 def go @@classvar = @@classvar*2 puts @@classvar end end instance = A.new instance.go #=> 2 instance = A.new instance.go #=> 4 -- variable is shared across instances
这是一个展示各种类型的演示
$variable class Test def initialize(arg1='kiwi') @instvar=arg1 @@classvar=@instvar+' told you so!!' localvar=@instvar end def print_instvar puts @instvar end def print_localvar puts @@classvar puts localvar end end var=Test.new var.print_instvar #=>"kiwi", it works because a @instance_var can be accessed inside the class var.print_localvar #=>undefined local variable or method 'localvar' for #<Test:0x2b36208 @instvar="kiwi"> (NameError).
这将打印两行“kiwi”和“kiwi told you so!!”,然后由于 #<Test:0x2b36208 @instvar="kiwi">(NameError)中未定义的局部变量或方法“localvar”而失败。为什么呢? 嗯,在方法 print_localvar 的范围内,不存在 localvar,它存在于方法 initialize 中(直到 GC 将其清除)。另一方面,类变量 '@@classvar' 和 '@instvar' 在整个类中都有效,并且对于 @@class 变量,在子类中也有效。
class SubTest < Test def print_classvar puts @@classvar end end newvar=SubTest.new #newvar is created and it has @@classvar with the same value as the var instance of Test!! newvar.print_classvar #=>kiwi told you so!!
类变量的范围包括父类和子类,这些变量可以在类之间存在,并且可以受到子类操作的影响;-)
class SubSubTest < Test
def print_classvar
puts @@classvar
end
def modify_classvar
@@classvar='kiwi kiwi waaai!!'
end
end
subtest=SubSubTest.new
subtest.modify_classvar #lets add a method that modifies the contents of @@classvar in SubSubTest
subtest.print_classvar
Test 的这个新的子类也具有 @@classvar,其值为原始值 newvar.print_classvar。@@classvar 的值已更改为“kiwi kiwi waaai!!”。这表明 @@classvar 在父类和子类之间是“共享”的。
当你没有将代码包含在任何范围限定符中,例如
@a = 33
它会影响默认范围,即一个名为“main”的对象。
例如,如果你有一个脚本是这样的
@a = 33 require 'other_script.rb'
而另一个脚本 other_script.rb 是这样的
puts @a
#=> 33
它们可以共享变量。
但是请注意,这两个脚本不共享局部变量。
通常当你处于一个类中时,你可以根据需要进行定义,例如。
class A a = 3 if a == 3 def go 3 end else def go 4 end end end
而且,procs 会“绑定”到它们周围的范围,例如
a = 3 b = proc { a } b.call # 3 -- it remembered what a was
但是,关键字“class”和“def”会创建一个*全新的*范围。
class A a = 3 def go return a # this won't work! end end
你可以使用 define_method 来绕过这个限制,它接受一个块并因此保留外部范围(注意你可以使用任何你想要的块,这里举个例子)。
class A a = 3 define_method(:go) { a } end
这里使用一个任意的块
a = 3 PROC = proc { a } # gotta use something besides a local # variable because that "class" makes us lose scope. class A define_method(:go, &PROC) end
或者这里
class A end a = 3 A.class_eval do define_method(:go) do puts a end end
二元“and”运算符将返回其两个操作数的逻辑合取。它与“&&”相同,但优先级较低。示例
a = 1 b = 2 c = nil puts "yay all my arguments are true" if a and b puts "oh no, one of my argument is false" if a and c
二元“or”运算符将返回其两个操作数的逻辑析取。它与“||”相同,但优先级较低。示例
a = nil b = "foo" c = a || b # c is set to "foo" it's the same as saying c = (a || b) c = a or b # c is set to nil it's the same as saying (c = a) || b which is not what you want.
- ↑ https://doc.ruby-lang.org.cn/core-2.4.0/doc/syntax/precedence_rdoc.html
- ↑ https://www.ruby-lang.org.cn/en/news/2015/12/25/ruby-2-3-0-released/
- ↑ http://blog.rubyeffect.com/ruby-2-3s-lonely-operator/
- ↑ https://bugs.ruby-lang.org/issues/11537
- ↑ http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html