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.
- ↑ http://ruby-doc.org/core-2.4.0/doc/syntax/precedence_rdoc.html
- ↑ https://www.ruby-lang.org/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