分解

通過將其元素分配給多個變數,可以快速分解任何陣列。一個簡單的例子:

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 *

分解是安全的,永遠不會引發錯誤。nils 被分配在沒有足夠元素的地方,在訪問超出範圍的索引時匹配 [] 運算子的行為:

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

在構建賦值的右側時捕獲值,因此使用與源和目標相同的變數是相對安全的。