我在阅读 The Ruby Way :
时遇到了以下代码class Array
def invert
each_with_object({}).with_index { |(elem, hash), index| hash[elem] = index }
end
end
我想确保我理解括号在(elem, hash)
中的作用。
第一种方法(each_with_object({})
)将为块生成两个对象。第一个对象是数组中的元素;第二个对象将是哈希。括号确保将这两个对象分配给不同的块变量。如果我改为使用{ |elem, index} #code }
,那么elem将是一个由元素和散列组成的数组。我认为这很清楚。
我的困惑在于,如果我没有链接这两种方法,我就不必使用括号,而是可以使用:each_with_object({}) { |elem, obj #code }
。
关于块变量中何时需要括号的规则是什么?为什么他们在这两个例子之间有所区别?我的简单解释是,当方法没有链接时,yield代码看起来像yield (elem, obj)
,但是当方法被链接时,代码看起来像yield([elem, obj], index)
。 (如果我们链接第三种方法,我们可以推测第二个数组会被传入)。它是否正确?从最后一个链接方法传入的对象不是数组吗?
我想而不是所有这些猜想,问题归结为:"链接接受块的方法时,yield语句是什么样的?
答案 0 :(得分:2)
您的问题仅与块和块变量相关。相反,它涉及“消除歧义”数组的规则。
让我们考虑你的例子:
localhost/Utilities.WebService/API/GetFileInfo
我们有:
[1,2,3].each_with_object({}).with_index {|(elem, hash), index| hash[elem] = index}
我们可以通过将它转换为数组来看到这个枚举器的元素:
enum0 = [1,2,3].each_with_object({})
#=> #<Enumerator: [1, 2, 3]:each_with_object({})>
我们接下来有:
enum0.to_a
#=> [[1, {}], [2, {}], [3, {}]]
您可能希望将enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:each_with_object({})>:with_index>
enum1.to_a
#=> [[[1, {}], 0], [[2, {}], 1], [[3, {}], 2]]
视为“复合枚举器”,但它只是一个枚举器。
您看到enum1
有三个要素。这些元素由Enumerator#each传递给块。第一个是:
enum1
如果我们有一个块变量,请说enum1.first
#=> [[1, {}], 0]
,那么
a
我们可以使用“消歧”以不同的方式打破这种情况。例如,我们可以写:
a #=> [[1, {}], 0]
现在让我们剔除所有元素:
a,b = [[1, {}], 0]
a #=> [1, {}]
b #=> 0
糟糕!那不是我们想要的。我们刚刚经历了“消除歧义”中的“暧昧”。我们需要写这个,以便我们的意图是明确的。我们通过添加括号来做到这一点。通过这样做,你告诉Ruby,“将这个位置的数组分解为其组成元素”。我们有:
a,b,c = [[1, {}], 0]
a #=> [1, {}]
b #=> 0
c #=> nil
消歧可能非常有用。例如,假设一个方法返回了数组:
(a,b),c = [[1, {}], 0]
a #=> 1
b #=> {}
c #=> 0
我们希望提取所有个人价值观。我们可以这样做:
[[1,[2,3],[[4,5],{a: 6}]],7]
同样,你必须记住括号只是意味着“将这个位置的数组分解为其组成元素”。
答案 1 :(得分:0)
规则是基本的:每个普查员都有一个“签名”。它产生两个参数,然后要传递的proc应该期望接收两个参数:
[1,2,3].each_with_index { |o, i| ...}
当对象可能被扩展时,如散列项,可以使用括号进行扩展。假设,迭代器产生一个数组,[*arr]
- 允许使用类似的操作。
以下示例可能会对此有所了解:
[1,2,3].each_with_object('first') # yielding |e, obj|
.with_index # yielding |elem, idx|
# but wait! elem might be expanded here ⇑⇑⇑⇑
# |(e, obj), idx|
.each_with_object('second') do |((elem, fst_obj), snd_idx), trd_obj|
puts "e: #{elem}, 1o: #{fst_obj}, 2i: #{snd_idx}, 3o: #{trd_obj}"
end
#⇒ e: 1, 1o: first, 2i: 0, 3o: second
#⇒ e: 2, 1o: first, 2i: 1, 3o: second
#⇒ e: 3, 1o: first, 2i: 2, 3o: second