分解
通過將其元素分配給多個變數,可以快速分解任何陣列。一個簡單的例子:
arr = [1, 2, 3]
# ---
a = arr[0]
b = arr[1]
c = arr[2]
# --- or, the same
a, b, c = arr
使用 splat 運算子(*
) 在變數之前放入一個未被其他變數捕獲的所有元素的陣列。如果沒有,則分配空陣列。一次分配中只能使用一個 splat:
a, *b = arr # a = 1; b = [2, 3]
a, *b, c = arr # a = 1; b = [2]; c = 3
a, b, c, *d = arr # a = 1; b = 2; c = 3; d = []
a, *b, *c = arr # SyntaxError: unexpected *
分解是安全的,永遠不會引發錯誤。nil
s 被分配在沒有足夠元素的地方,在訪問超出範圍的索引時匹配 []
運算子的行為:
arr[9000] # => nil
a, b, c, d = arr # a = 1; b = 2; c = 3; d = nil
分解試圖隱式地在被分配的物件上呼叫 to_ary
。通過在你的型別中實現此方法,你可以分解它:
class Foo
def to_ary
[1, 2]
end
end
a, b = Foo.new # a = 1; b = 2
如果被分解的物件不是 respond_to?
to_ary
,則將其視為單元素陣列:
1.respond_to?(:to_ary) # => false
a, b = 1 # a = 1; b = nil
分解也可以通過使用 ()
分隔的分解表示式代替單獨的元素來巢狀 :
arr = [1, [2, 3, 4], 5, 6]
a, (b, *c), *d = arr # a = 1; b = 2; c = [3, 4]; d = [5, 6]
# ^^^^^
這實際上與 splat 相反。
實際上,任何分解表示式都可以由 ()
分隔。但是對於第一級分解是可選的。
a, b = [1, 2]
(a, b) = [1, 2] # the same thing
邊緣情況: 單個識別符號不能用作解構模式,無論是外部還是巢狀模式:
(a) = [1] # SyntaxError
a, (b) = [1, [2]] # SyntaxError
將陣列文字指定給解構表示式時,可以省略外部 []
:
a, b = [1, 2]
a, b = 1, 2 # exactly the same
這稱為並行分配,但它在引擎蓋下使用相同的分解。這對於交換變數的值而不使用額外的臨時變數特別方便:
t = a; a = b; b = t # an obvious way
a, b = b, a # an idiomatic way
(a, b) = [b, a] # ...and how it works
在構建賦值的右側時捕獲值,因此使用與源和目標相同的變數是相對安全的。