提问人:collimarco 提问时间:8/2/2009 最后编辑:user513951collimarco 更新时间:9/12/2022 访问量:154232
map(&:name) 在 Ruby 中是什么意思?
What does map(&:name) mean in Ruby?
问:
我在 RailsCast 中找到了这段代码:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
the in 是什么意思?(&:name)
map(&:name)
答:
它是tags.map { |tag| tag.name }.join(' ')
评论
&
to_proc
它相当于
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
它是tags.map(&:name.to_proc).join(' ')
如果是一个带有方法的对象,那么你可以把它传递给一个方法,作为 ,该方法将调用并将其用作方法的块。foo
to_proc
&foo
foo.to_proc
该方法最初是由 ActiveSupport 添加的,但已集成到 Ruby 1.8.7 中。这是它的实现:Symbol#to_proc
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
评论
&
tags.map(&:name.to_proc).join(' ')
tags.map { |tag| tag.name }
tags.map(&:name.to_proc)
另一个很酷的速记,许多人不知道,是
array.each(&method(:foo))
这是
array.each { |element| foo(element) }
通过调用,我们从中获取了一个对象,该对象表示其方法,并使用 表示它有一个方法将其转换为 .method(:foo)
Method
self
foo
&
to_proc
Proc
当您想以无点风格做事时,这非常有用。例如,检查数组中是否有任何字符串等于字符串。有一种常规方法:"foo"
["bar", "baz", "foo"].any? { |str| str == "foo" }
还有一种无点的方式:
["bar", "baz", "foo"].any?(&"foo".method(:==))
首选方式应该是最易读的方式。
评论
array.each{|e| foo(e)}
仍然更短:-) +1 反正
&method
[1,2,3].map(&Array.method(:new))
[[nil], [nil, nil], [nil, nil, nil]]
同时,我们也要注意,与号和魔术可以与任何类一起使用,而不仅仅是符号。许多 Ruby 主义者选择在 Array 类上定义:#to_proc
#to_proc
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
与号的工作原理是在其操作数上发送消息,在上面的代码中,该操作数属于 Array 类。由于我在 Array 上定义了方法,因此该行变为:&
to_proc
#to_proc
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
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
使用此代码,在执行时,Ruby 将第一个输入拆分为 1 和 'a' 以给出 1 和 'a' 以导致错误,因为 Fixnum 对象 1 没有 self 方法(即 :first)。print [[1,'a'],[2,'b'],[3,'c']].map(&:first)
[1,'a']
obj
args*
何时执行;[[1,'a'],[2,'b'],[3,'c']].map(&:first)
:first
是一个 Symbol 对象,因此当将 map 方法作为参数提供给 Symbol#to_proc 时,将调用 Symbol#。&:first
map 使用参数向 :first.to_proc 发送调用消息,例如,执行。
[1,'a']
:first.to_proc.call([1,'a'])
例如,Symbol 类中的to_proc过程向带有参数 (:first) 的数组对象 () 发送消息。
[1,'a']
[1,'a'].send(:first)
遍历 object 中的其余元素。
[[1,'a'],[2,'b'],[3,'c']]
这与执行表达式相同。[[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
评论
[1,2,3,4,5,6].inject(&:+)
:+.to_proc
Proc.new |obj, *args| { obj.send(self, *args) }
{ |m, o| m.+(o) }
这里正在发生两件事,了解这两件事很重要。
如其他答案中所述,正在调用该方法。Symbol#to_proc
但是在符号上调用的原因是因为它被作为块参数传递给。在方法调用中,将参数放在参数的前面会导致以这种方式传递它。这适用于任何 Ruby 方法,而不仅仅是符号。to_proc
map
&
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)
它被转换为 a,因为它是作为块传入的。我们可以通过尝试在没有 & 符号的情况下传递一个 proc 来证明这一点:Symbol
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
如下同:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end
这是指向标记对象方法的符号。
当我们传递给 时,它将被视为一个 proc 对象。
简称,充当::name
name
&:name
map
name
tags.map(&:name)
tags.map do |tag|
tag.name
end
(&:name) 是 (&:name.to_proc) 的缩写,它与tags.map{ |t| t.name }.join(' ')
to_proc实际上是用 C 语言实现的
tags.map(&:name)
与
tags.map{|tag| tag.name}
&:name
仅使用符号作为要调用的方法名称。
评论
tags.map(&:name, &:id)
tags.map { |t| t.name.to_s << t.age.to_s }
这意味着
array.each(&:to_sym.to_proc)
虽然我们已经有很好的答案,但从初学者的角度来看,我想添加额外的信息:
map(&:name) 在 Ruby 中是什么意思?
这意味着,您正在将另一个方法作为参数传递给 map 函数。 (实际上,您传递的是一个转换为过程的符号。但这在这种特殊情况下并不那么重要)。
重要的是,您有一个名称,map 方法将使用它作为参数,而不是传统样式。method
name
block
map(&:name) 接受一个可枚举对象(在本例中为 tags)并为每个元素/标记运行 name 方法,输出该方法的每个返回值。
它是
array.map { |element| element.name }
它返回 element(tag) 名称的数组
它基本上对数组中的每个标签执行方法调用。tag.name
它是一种简化的红宝石速记。
首先,是 的快捷方式,其中返回一个(类似于 lambda 的东西,但不完全相同),当使用对象作为(第一个)参数调用时,将调用该对象的方法。&:name
&:name.to_proc
:name.to_proc
Proc
name
其次,当 将传递给 的块转换为 时,当应用于 .&
def foo(&block) ... end
foo
Proc
Proc
因此,是一个将对象作为参数并调用其方法的块,即 .&:name.to_proc
name
{ |o| o.name }
Ruby 中没有 &: 运算符。您看到的是应用于 :symbol 的 & 运算符。
在方法参数列表中,& 运算符获取其操作数,将其转换为 Proc 对象(如果尚未)(通过调用 to_proc),并将其传递给方法,就好像使用了块一样。
my_proc = Proc.new { 放 “foo” }
my_method_call(&my_proc) # 等同于: my_method_call { 放 “foo” }
评论
tags.map &:name