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

col*_*rco 483 ruby syntax operators parameter-passing

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

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end
Run Code Online (Sandbox Code Playgroud)

什么是(&:name)map(&:name)意味着什么?

Jos*_*Lee 510

这是简写 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
Run Code Online (Sandbox Code Playgroud)

  • tags.map(:name.to_proc)本身就是tags.map {| tag |的缩写 标签名称 } (89认同)
  • 这是一个比我更好的答案. (40认同)
  • Symbol#to_proc是用C实现的,而不是用Ruby实现的,但这就是它在Ruby中的样子. (5认同)
  • @AndrewGrimm它首先在Ruby on Rails中添加,使用该代码.然后在1.8.7版本中将其添加为本机ruby功能. (5认同)
  • 这不是有效的ruby代码,你仍然需要`&`,即`tags.map(&:name.to_proc).join('')` (4认同)
  • @SimoneCarletti - 当`tags.map {| tag | tag.name}`实际上是`tags.map(&:name.to_proc)`,它本身并不完全是速记.这是因为当将procs传递给使用yield的方法并因此需要块时,可以使用&运算符将procs转换为块.(参见Ruby文档[here](http://www.ruby-doc.org/core-2.0/doc/syntax/calling_methods_rdoc.html#label-Proc+to+Block+Conversion)).正如Josh Lee在上面的帖子中所示,符号也可以转换为procs,然后可以将其转换为块,这是必要的,因为map使用块. (3认同)
  • 很棒的答案!我认为显示整个Symbol实现类的链接会很有用.https://github.com/rubinius/rubinius/blob/master/kernel/common/symbol19.rb (2认同)
  • @JaredBeck做对了:&符只是告诉ruby _"这个论点是块,如果它还没有,请尽力使它成为一个"_ (2认同)

Ger*_*rry 171

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

array.each(&method(:foo))
Run Code Online (Sandbox Code Playgroud)

这是一个简写

array.each { |element| foo(element) }
Run Code Online (Sandbox Code Playgroud)

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

当你想做无点风格的事情时,这非常有用.一个示例是检查数组中是否有与字符串相等的字符串"foo".有传统方式:

["bar", "baz", "foo"].any? { |str| str == "foo" }
Run Code Online (Sandbox Code Playgroud)

并且有无点的方式:

["bar", "baz", "foo"].any?(&"foo".method(:==))
Run Code Online (Sandbox Code Playgroud)

首选方式应该是最易读的方法.

  • `array.each {| E | foo(e)}`还是更短:-) +1反正 (25认同)
  • @JaredBeck Yeap!更短但不是免费的:) (6认同)
  • @finishingmove是的,我想.试试这个`[1,2,3] .map(&Array.method(:new))` (3认同)

Sop*_*ert 76

它相当于

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end
Run Code Online (Sandbox Code Playgroud)


Bor*_*cky 44

我们还要注意,&符号#to_proc魔法可以适用于任何类,而不仅仅是符号.许多Rubyist选择#to_proc在Array类上定义:

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

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Run Code Online (Sandbox Code Playgroud)

Ampersand &通过to_proc在其操作数上发送消息来工作,在上面的代码中,该操作数是Array类.由于我#to_proc在Array上定义了方法,因此该行变为:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
Run Code Online (Sandbox Code Playgroud)


Oli*_* N. 38

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

  • @collimarco:正如jleedev在他的回答中所说,一元`&`操作符在其操作数上调用`to_proc`.因此它并不特定于map方法,并且实际上适用于采用块并将一个或多个参数传递给块的任何方法. (7认同)

Alb*_*ing 34

tags.map(&:name)
Run Code Online (Sandbox Code Playgroud)

是相同的

tags.map{|tag| tag.name}
Run Code Online (Sandbox Code Playgroud)

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


pro*_*eek 14

Josh Lee的答案几乎是正确的,除了等效的Ruby代码应该如下.

class Symbol
  def to_proc
    Proc.new do |receiver|
      receiver.send self
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

与此代码,当print [[1,'a'],[2,'b'],[3,'c']].map(&:first)被执行时,红宝石分割第一输入[1,'a']到1和"a",得到obj1和args*"a"到引起错误作为Fixnum对象物1不具有自我方法(其为:第一).


什么时候[[1,'a'],[2,'b'],[3,'c']].map(&:first)执行;

  1. :first是一个Symbol对象,因此当&:first将map方法作为参数赋予时,将调用Symbol#to_proc.

  2. map将调用消息发送到:first.to_proc with parameter [1,'a'],例如,:first.to_proc.call([1,'a'])执行.

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

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

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

  • Josh Lee 的答案是_绝对_正确的,正如你通过考虑 `[1,2,3,4,5,6].inject(&:+)` 所看到的那样 - 注入需要一个带有两个参数(memo 和 item)的 lambda 和`:+.to_proc` 提供它 - `Proc.new |obj, *args| { obj.send(self, *args) }` 或 `{ |m, o| m.+(o) }` (2认同)

dev*_*ppy 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)
Run Code Online (Sandbox Code Playgroud)

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"]
Run Code Online (Sandbox Code Playgroud)

即使它不需要转换,该方法也不会知道如何使用它,因为它需要一个块参数.传递它&给出.map了它期望的块.


tes*_*sie 5

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

to_proc实际上是用C实现的


小智 5

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

它是一个简写

array.map { |element| element.name }
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*oph 5

First,&:name是 的快捷方式&:name.to_proc,其中:name.to_proc返回一个Proc(与 lambda 类似但不相同的东西),当使用对象作为(第一个)参数调用时,调用name该对象上的方法。

其次,虽然&indef foo(&block) ... end将传递给 a 的块转换foo为 a Proc,但应用于 a 时,它会执行相反的操作Proc

因此,&:name.to_proc是一个以对象作为参数并调用name其方法的块,即{ |o| o.name }