0

真的不知道如何命名这个问题。

考虑一个任意散列(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)
4

4 回答 4

1

默认情况下,没有。

要执行您想要的操作,您需要向 Array 类添加一个方法,该方法会以您想要的方式打印出来,例如:

class Array
  def bar
    puts "#{self[0]}: #{self[1]}"
  end
end

有了它,ENV.each(&:bar)就会做你所期望的。

也就是说,我不会推荐这个。只有当实用程序远远超过未来冲突的可能性时,才应该添加到基类中,并且该方法高度专门用于其中至少有 2 个元素的数组。

不相关,但连接字符串 via+比使用插值要慢得多。它不必要地创建了额外的对象。

于 2012-10-02T00:36:42.230 回答
1

在您的示例中,使用&: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

于 2012-10-02T00:58:49.520 回答
1

通常,如果集合的元素响应该方法,这是可能的。例如:

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)
于 2012-10-02T00:59:17.403 回答
1

您可以通过执行以下操作来摆脱两个块变量并使用一个:

each{|kv| puts kv.join(": ")}
于 2012-10-02T05:16:17.650 回答