分解
通过将其元素分配给多个变量,可以快速分解任何数组。一个简单的例子:
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
在构建赋值的右侧时捕获值,因此使用与源和目标相同的变量是相对安全的。