我在RailsCast中找到了这段代码:
1 2 3
| def tag_names
@tag_names || tags.map(&:name).join(' ')
end |
map(&:name)中的(&:name)是什么意思?
-
顺便说一下,我听说这个叫做"椒盐卷饼结肠"。
-
哈哈。 我知道这是一个&符号。 我从来没有听说它叫做"椒盐卷饼",但这是有道理的。
-
您也可以删除括号tags.map &:name以获得额外最短的条目。
-
称之为"椒盐卷饼结肠"是误导性的,虽然引人注目。 红宝石中没有"&amp ;:"。 &符号(&)是"一元&符号运算符",具有一起推动符号。 如果有的话,它是一个"椒盐卷饼符号"。 只是说。
-
tags.map(&:name)是来自tags.map {| s |的排序s.name}
-
"椒盐卷饼结肠"听起来像一个痛苦的医疗条件...但我喜欢这个符号的名称:)
-
brianstorti.com/understanding-ruby-idiom-map-with-symbol
它是tags.map(&:name.to_proc).join(' ')的简写
如果foo是具有to_proc方法的对象,则可以将其传递给&foo的方法,该方法将调用foo.to_proc并将其用作方法的块。
Symbol#to_proc方法最初由ActiveSupport添加,但已集成到Ruby 1.8.7中。这是它的实现:
1 2 3 4 5 6 7
| class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end |
-
这是一个比我更好的答案。
-
tags.map(:name.to_proc)本身就是tags.map {| tag |的缩写标签名称 }
-
这不是有效的ruby代码,你仍然需要&,即tags.map(&:name.to_proc).join(' ')
-
@banister谢谢,修好。
-
Symbol#to_proc是用C实现的,而不是用Ruby实现的,但这就是它在Ruby中的样子。
-
@banister我认为你可以在没有to_proc的情况下编写tags.map(&:name).join(' ')
-
"一个块可以使用文字块或者包含对前缀为&符号的Proc或Method对象的引用的参数与方法调用相关联。" bit.ly/n8GpYw
-
@AndrewGrimm它首先在Ruby on Rails中添加,使用该代码。然后在1.8.7版本中将其添加为本机ruby功能。
-
很棒的答案!我认为显示整个Symbol实现类的链接会很有用。 github.com/rubinius/rubinius/blob/master/kernel/common/…
-
@SimoneCarletti - 虽然tags.map { |tag| tag.name }实际上是tags.map(&:name.to_proc)所做的,但它本身并不完全是速记。这是因为可以使用& amp;转换为块。运算符,当它们传递给使用yield的方法并因此需要块时。 (请参阅此处的Ruby文档)。正如Josh Lee在上面的帖子中所示,符号也可以转换为procs,然后可以将其转换为块,这是必要的,因为map使用块。
-
我发现了一篇很棒的文章来解释Ruby中更详细的&符号运算符,希望它能帮助人们。"foo"跟着"&"可以是符号或对象。 ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby
-
@JaredBeck做对了:&符只是告诉红宝石"这个论点是块,如果它还没有,请尽力使它成为一个"
-
您应该使用#__send__而不是#send,因为它更安全。对象可以出于某种原因覆盖send(例如,发送电子邮件),但如果对#__send__执行相同操作,则Ruby VM会发出警告。
-
它没有谈到符号如何映射/连接到实际方法。触发的符号听起来都很好。但符号是空的,它们如何成为代码块。
-
它不仅仅是一个速记,而且还有20%更快,更惯用的红宝石代码。
-
If foo is an object with a to_proc method, then you can pass it to a method as &foo。请举例说明,这对我来说太抽象了。什么是&foo语言结构甚至被称为?不知道谷歌要做什么使这更清楚。
另一个很酷的简写,很多人都不知道
1
| array.each(&method(:foo)) |
这是一个简写
1
| array.each { |element| foo(element) } |
通过调用method(:foo),我们从self获取了一个表示其foo方法的Method对象,并使用&表示它有一个to_proc方法,将其转换为Proc。
当你想做无点风格的事情时,这非常有用。一个示例是检查数组中是否有任何字符串等于字符串"foo"。有传统方式:
1
| ["bar","baz","foo"].any? { |str| str =="foo" } |
并且有无点的方式:
1
| ["bar","baz","foo"].any?(&"foo".method(:==)) |
首选方式应该是最易读的方法。
-
array.each{|e| foo(e)}仍然更短:-) +1反正
-
@JaredBeck Yeap!更短但不是免费的:)
-
而且速度惊人的快。
-
你能用&method映射另一个类的构造函数吗?
-
@finishingmove是的,我想。试试这个[1,2,3].map(&Array.method(:new))
-
太棒了,谢谢@Gerry :)
-
正是我在寻找的!
它相当于
1 2 3
| def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end |
虽然我们还要注意,&符号#to_proc魔法可以适用于任何类,而不仅仅是符号。许多Rubyist选择在Array类上定义#to_proc:
1 2 3 4 5 6 7 8 9 10
| class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!","Goodbye world!"] |
Ampersand &通过在其操作数上发送to_proc消息来工作,在上面的代码中,该操作数是Array类。由于我在Array上定义了#to_proc方法,因此该行变为:
1
| [ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) } |
它是tags.map { |tag| tag.name }.join(' ')的简写
-
不,它在Ruby 1.8.7及更高版本中。
-
这是一个简单的地图成语或Ruby总是解释'&'以某种特定的方式?
-
@Chuck谢谢,还原为正确。
-
@collimarco:正如jleedev在他的回答中所说,一元&运算符在其操作数上调用to_proc。因此它并不特定于map方法,并且实际上适用于采用块并将一个或多个参数传递给块的任何方法。
是相同的
1
| tags.map{|tag| tag.name} |
&:name只使用符号作为要调用的方法名称。
-
我正在寻找的答案,而不是特别针对过程(但那是请求者的问题)
-
很好的答案! 为我澄清了。
Josh Lee的答案几乎是正确的,除了等效的Ruby代码应该如下。
1 2 3 4 5 6 7
| class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end |
不
1 2 3 4 5 6 7
| 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没有方法自我(这是:第一)。
执行[[1,'a'],[2,'b'],[3,'c']].map(&:first)时;
:first是一个Symbol对象,因此当&:first作为参数提供给map方法时,将调用Symbol#to_proc。
map将调用消息发送到:first.to_proc,参数为[1,'a'],例如执行:first.to_proc.call([1,'a'])。
Symbol类中的to_proc过程使用参数(:first)向数组对象([1,'a'])发送发送消息,例如执行[1,'a'].send(:first)。
迭代[[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(&:+)看到 - inject需要一个带有两个参数的lambda(memo和item),:+.to_proc传递它 - Proc.new |obj, *args| { obj.send(self, *args) }或{ |m, o| m.+(o) }
这里发生了两件事情,理解两者都很重要。
如其他答案中所述,正在调用Symbol#to_proc方法。
但是在符号上调用to_proc的原因是因为它作为块参数传递给map。在方法调用中将&放在参数前面会导致它以这种方式传递。对于任何Ruby方法都是如此,而不仅仅是带符号的map。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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而不使用&符号来显示:
1 2 3 4 5 6 7 8 9 10 11
| 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它所期望的块。
-
老实说,这是最好的答案。你解释了&符背后的机制以及为什么我们最终会得到一个proc,直到你的回答我都没有得到。谢谢。
(&amp;:name)是(&amp;:name.to_proc)的缩写,与tags.map{ |t| t.name }.join(' ')相同
to_proc实际上是用C实现的
map(&amp;:name)接受一个可枚举的对象(在您的情况下为标记)并为每个元素/标记运行name方法,从方法输出每个返回的值。
这是一个简写
1
| array.map { |element| element.name } |
返回元素(标记)名称的数组
虽然我们已经有了很好的答案,但从初学者的角度来看,我想添加其他信息:
What does map(&:name) mean in Ruby?
这意味着,您将另一个方法作为参数传递给map函数。
(实际上你传递的是一个符号,它被转换成一个过程。但在这个特殊情况下,这并不重要)。
重要的是你有一个名为name的method,它将被map方法用作参数而不是传统的block样式。
它基本上对数组中的每个标签执行方法调用tag.name。
这是一个简化的红宝石简写。
它的意思是
1
| array.each(&:to_sym.to_proc) |
这里:name是指向标签对象的方法name的符号。
当我们将&:name传递给map时,它会将name视为proc对象。
简而言之,tags.map(&:name)充当:
1 2 3
| tags.map do |tag|
tag.name
end |
它如下:
1 2 3 4 5 6
| def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end |