我在RailsCast中找到了这段代码:

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end

map(&:name)中的(&:name)是什么意思?


当前回答

另一个很酷的简写,很多人不知道,是

array.each(&method(:foo))

这是一个简写

array.each { |element| foo(element) }

通过调用method(:foo),我们从self中获取了一个method对象,该对象表示它的foo方法,并使用&表示它有一个to_proc方法,该方法将它转换为Proc。

这是非常有用的,当你想做点自由风格的事情。一个例子是检查数组中是否有字符串等于字符串“foo”。有一种传统的方式:

["bar", "baz", "foo"].any? { |str| str == "foo" }

还有一种简单的方法:

["bar", "baz", "foo"].any?(&"foo".method(:==))

首选的方式应该是最易读的方式。

其他回答

如下所示:

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end

同时让我们也注意到& #to_proc魔法可以对任何类工作,而不仅仅是符号。很多ruby会选择在Array类上定义#to_proc:

class Array
  def to_proc
    proc { |receiver| receiver.send *self }
  end
end

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]

&的工作原理是在其操作数上发送to_proc消息,在上面的代码中,操作数属于Array类。因为我在Array上定义了#to_proc方法,所以这一行变成:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }

它是tags.map(&:name.to_proc)的简写。加入(' ')

如果foo是一个带有to_proc方法的对象,那么你可以将它传递给一个名为&foo的方法,该方法将调用foo。To_proc并使用它作为方法的块。

Symbol#to_proc方法最初是由ActiveSupport添加的,但已经集成到Ruby 1.8.7中。这是它的实现:

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

它等价于

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end

Josh Lee的回答几乎是正确的,除了等价的Ruby代码应该如下所示。

class Symbol
  def to_proc
    Proc.new do |receiver|
      receiver.send self
    end
  end
end

not

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

使用这段代码,当print [[1,'a'],[2,'b'],[3,'c']].map(&:first)执行时,Ruby将第一个输入[1,'a']分割为1和'a'以给出obj 1和args* 'a'以引起错误,因为Fixnum对象1没有方法self(即:first)。


当[[1,a), (2, ' b '], [3, ' c ']] . map(&:首先)执行;

:first是一个Symbol对象,所以当&:first作为参数被赋给一个map方法时,Symbol#to_proc将被调用。 地图将呼叫信息发送到:first。参数[1,'a']的To_proc,例如:first.to_proc.call([1,'a'])被执行。 Symbol类中的to_proc过程以参数(:first)向数组对象([1,'a'])发送发送消息,例如,[1,'a'].send(:first)被执行。 遍历[[1,'a'],[2,'b'],[3,'c']]对象中的其余元素。

这是一样的执行[[1,' '],[2,' b '], [3, ' c ']]。Map (|e| e.first)表达式。