map(&:name)在Ruby中意味着什么?

时间:2009-08-01 17:35:59

标签: ruby syntax operators parameter-passing

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

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

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

17 个答案:

答案 0 :(得分:499)

这是tags.map(&:name.to_proc).join(' ')

的简写

如果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

答案 1 :(得分:166)

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

array.each(&method(:foo))

的简写
array.each { |element| foo(element) }

通过调用method(:foo),我们从Method获取了代表其self方法的foo个对象,并使用&表示它有to_proc {1}} method将其转换为Proc

当您想要执行无点样式时,这非常有用。一个示例是检查数组中是否有任何字符串等于字符串"foo"。有传统方式:

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

并且有无点的方式:

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

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

答案 2 :(得分:76)

相当于

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

答案 3 :(得分:42)

虽然我们还要注意,&符号#to_proc魔法可以适用于任何类,而不仅仅是符号。许多Rubyist选择在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!' ) }

答案 4 :(得分:37)

这是tags.map { |tag| tag.name }.join(' ')

的简写

答案 5 :(得分:30)

tags.map(&:name)

相同
tags.map{|tag| tag.name}

&:name只使用符号作为要调用的方法名称。

答案 6 :(得分:14)

Josh Lee的答案几乎是正确的,只是等效的Ruby代码应该如下所示。

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

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)时;

  1. :first是一个Symbol对象,因此当&:first作为参数提供给map方法时,会调用Symbol#to_proc。

  2. map将调用消息发送到:first.to_proc,参数为[1,'a'],例如,:first.to_proc.call([1,'a'])被执行。

  3. 符号类中的
  4. to_proc过程使用参数(:first)向数组对象([1,'a'])发送发送消息,例如,执行[1,'a'].send(:first)

  5. 迭代[[1,'a'],[2,'b'],[3,'c']]对象中的其余元素。

  6. 这与执行[[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)表达式相同。

答案 7 :(得分:11)

这里发生了两件事情,理解这两件事很重要。

如其他答案所述,正在调用Symbol#to_proc方法。

但是在符号上调用to_proc的原因是因为它作为块参数传递给map。在方法调用中将&放在参数前面会导致它以这种方式传递。对于任何Ruby方法都是如此,而不仅仅是map带符号。

def some_method(*args, &block)
  puts "args: #{args.inspect}"
  puts "block: #{block.inspect}"
end

some_method(:whatever)
# args: [:whatever]
# block: nil

some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>

some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)

Symbol转换为Proc,因为它作为一个块传入。我们可以通过尝试将proc传递给.map而不使用&符号来显示:

arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true

arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)

arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]

即使它不需要转换,该方法也不知道如何使用它,因为它需要一个块参数。通过&传递它会使.map阻止它所需的块。

答案 8 :(得分:5)

(&amp;:name)是(&amp;:name.to_proc)的缩写,与tags.map{ |t| t.name }.join(' ')相同

to_proc实际上是用C

实现的

答案 9 :(得分:3)

首先,@estudiantes_seleccionados&:name的快捷方式,其中&:name.to_proc返回的:name.to_proc(与lambda类似但不相同)与作为第一个参数的对象,对该对象调用Proc方法。

第二,虽然name中的&将传递给def foo(&block) ... end的块转换为foo,但应用于Proc时却相反。 / p>

因此,Proc是一个以对象为参数并在其上调用&:name.to_proc方法的块,即i。 e。 name

答案 10 :(得分:2)

map(&:name)接受一个可枚举的对象(在您的情况下为标签)并为每个元素/标签运行name方法,并从该方法输出每个返回的值。

这是速记

myString2 = "i Am New To Python,
             trying to learn Different things.
             need your help in this Case."

返回元素(标签)名称的数组

答案 11 :(得分:2)

虽然我们已经有了很好的答案,但从初学者的角度来看,我想添加其他信息:

  

map(&amp;:name)在Ruby中意味着什么?

这意味着,您将另一个方法作为参数传递给map函数。 (实际上,你正在传递一个转换成proc的符号。但在这种特殊情况下,这并不重要。)

重要的是,您有method名为name的地图方法将用作参数而不是传统的block样式。

答案 12 :(得分:1)

换个词和箭头:

enter image description here

答案 13 :(得分:1)

意味着

array.each(&:to_sym.to_proc)

答案 14 :(得分:1)

此处:name是指向标记对象的方法name的符号。 当我们将&:name传递给map时,它会将name视为proc对象。 简而言之,tags.map(&:name)充当:

tags.map do |tag|
  tag.name
end

答案 15 :(得分:0)

它基本上在数组中的每个标签上执行方法调用tag.name

这是简化的红宝石缩写。

答案 16 :(得分:0)

与以下相同:

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