Ruby和符号冒号快捷方式

341

可能重复:
What does map(&:name) mean in Ruby?

在 Ruby 中,我知道如果这样做:

some_objects.each(&:foo)

这和

some_objects.each { |obj| obj.foo }

也就是说,&:foo 创建了块 { |obj| obj.foo },并将其转换为 Proc,并将其传递给 each 方法。为什么会这样工作?这只是 Ruby 的特殊情况,还是有其他原因使其能够正常工作?


这也被称为“椒盐脆饼”语法(Pretzel Colon Syntax)。 - anothermh
2个回答

507

你的问题可以说是错误的。这里发生的不是“和冒号”,而是“和对象”。在这种情况下,冒号是用于符号的。所以有&:foo

& 调用了对象上的 to_proc 方法,并将其作为块传递给方法。在 Ruby 中,to_proc 是在 Symbol 上实现的,因此这两个调用是等效的:

something {|i| i.foo }
something(&:foo)

总结一下:在Ruby中,&会调用对象的to_proc方法并将其作为块传递给方法,在Symbol上实现了to_proc方法。


90
更准确地说,& 符号会展开 Proc 对象,使其被作为字面块传递。仅当该对象本身不是 Proc 对象时,才会调用 to_proc 方法。 - Jörg W Mittag
7
@Steve:不,这也适用于1.8.7版本。p RUBY_VERSION # => "1.8.7" p ["a", "b", "c"].map(&:upcase) # => ["A", "B", "C"] - August Lilleaas
1
http://ruby-doc.org/core/ 是针对1.8.7版本的,而 http://ruby-doc.org/core-1.8.7/ 则是1.8.7版本的等效页面。这里是入口链接:http://ruby-doc.org/core-1.8.7/classes/Symbol.html#M000086。 - August Lilleaas
1
谢谢,那很有道理。很高兴知道它在Ruby 1.8.7和1.9中存在。 - Allan Grant
2
谢谢。虽然我已经使用这种约定多年,但这是我第一次真正理解 &: 的作用。 - David Hempy
显示剩余8条评论

93

使用“&”符号和“#”符号的组合并没有什么特别之处。这里有一个(滥用)正则表达式的示例:

class Regexp
  def to_proc
    ->(str) { self =~ str ; $1 }
  end
end
%w(station nation information).map &/(.*)ion/

=> ["stat", "nat", "informat"]

或整数。

class Integer
  def to_proc
    ->(arr) { arr[self] }
  end
end

arr = [[*3..7],[*14..27],[*?a..?z]]
arr.map &4
=> [7, 18, "e"]

当你拥有arr.map &4时,谁还需要arr.map(&:fifth)呢?


5
比起被标记为正确的答案,我更喜欢这个例子。 - Daniel Viglione
很有趣看到[*3..7]的语法。我没想到你可以这样展开! - Ben Coppock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接