真的不知道如何命名这个问题。
考虑一个任意散列(ENV 很方便):
ENV.each { |key, val| puts key + ': ' + val }
LC_MESSAGES: en_US.utf-8
LC_COLLATE: en_US.utf-8
PWD: /Users/baller/ive_fallen_and_i_cant_get_up
LC_MONETARY: en_US.utf-8
是否可以使用 &: 速记来做到这一点?
foo.each(&:bar)
默认情况下,没有。
要执行您想要的操作,您需要向 Array 类添加一个方法,该方法会以您想要的方式打印出来,例如:
class Array
def bar
puts "#{self[0]}: #{self[1]}"
end
end
有了它,ENV.each(&:bar)
就会做你所期望的。
也就是说,我不会推荐这个。只有当实用程序远远超过未来冲突的可能性时,才应该添加到基类中,并且该方法高度专门用于其中至少有 2 个元素的数组。
不相关,但连接字符串 via+
比使用插值要慢得多。它不必要地创建了额外的对象。
在您的示例中,使用&:bar
代替块将导致在#to_proc
给定对象上被调用,在本例中为符号:bar
。Ruby 中 Symbol的#to_proc
实现基本上扩展foo.each(&:bar)
为foo.each { |i| i.bar }
. 由于哈希产生了两个参数,i
因此在此示例中是键值 args 的数组。这就是为什么您必须扩展Array
(如@x1a4 所述)以使您的哈希按预期对待 &:bar 。
作为替代方案,您可以创建自己的类来响应#to_proc
或简单地将您的块实现为 Proc:
class Bar
def to_proc
Proc.new { |key, val| puts key + ': ' + val }
end
end
bar = Bar.new
# or
bar = Proc.new { |key, val| puts key + ': ' + val }
使用 bar 的句柄,您可以将 &bar 代替块传递给像 ENV 这样的哈希。所以给定一个哈希值,foo:
foo.each(&bar)
关于这个主题的更多阅读的好帖子:http ://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
通常,如果集合的元素响应该方法,这是可能的。例如:
class Foo
attr_reader :bar
def initialize(bar)
@bar = bar
end
end
foos = [Foo.new("one"), Foo.new("two"), Foo.new("three")]
p foos.map(&:bar) #=> ["one", "two", "three"]
这是有效的,因为&symbol
它是 的语法糖symbol.to_proc
,它反过来会产生一些魔法来返回一个块,该块将该消息发送到它作为参数接收的对象。
虽然这不适用于您的示例(因为中的对象ENV
不响应:bar
),但您可以使用以下方法传递一个存储在变量中的块&
:
block = lambda { |key, value| puts "#{key}: #{value}" }
ENV.each(&block)
您可以通过执行以下操作来摆脱两个块变量并使用一个:
each{|kv| puts kv.join(": ")}