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

发布于 2024-10-31 10:29:57 字数 296 浏览 7 评论 0原文

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

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

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

I found this code in a RailsCast:

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

What does the (&:name) in map(&:name) mean?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

兮颜 2024-11-07 10:29:58

首先,&:name&:name.to_proc 的快捷方式,其中 :name.to_proc 返回一个 Proc< /code> (类似于 lambda,但不完全相同),当使用对象作为(第一个)参数调用时,会调用该对象的 name 方法。

其次, while def foo(&block) ... end 中的 & 将传递给 foo 的块转换为 Proc,当应用于 Proc 时,它会执行相反的操作。

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

First, &:name is a shortcut for &:name.to_proc, where :name.to_proc returns a Proc (something that is similar, but not identical to a lambda) that when called with an object as (first) argument, calls the name method on that object.

Second, while & in def foo(&block) ... end converts a block passed to foo to a Proc, it does the opposite when applied to a Proc.

Thus, &:name.to_proc is a block that takes an object as argument and calls the name method on it, i. e. { |o| o.name }.

長街聽風 2024-11-07 10:29:58

尽管我们已经有了很好的答案,但从初学者的角度来看,我想添加额外的信息:

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

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

重要的是您有一个名为 namemethod,map 方法将使用它作为参数,而不是传统的 block 样式。

Although we have great answers already, looking through a perspective of a beginner I'd like to add the additional information:

What does map(&:name) mean in Ruby?

This means, that you are passing another method as parameter to the map function.
(In reality you're passing a symbol that gets converted into a proc. But this isn't that important in this particular case).

What is important is that you have a method named name that will be used by the map method as an argument instead of the traditional block style.

罪#恶を代价 2024-11-07 10:29:58

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

这是一个简化的 Ruby 简写。

It basically execute the method call tag.name on each tags in the array.

It is a simplified ruby shorthand.

幸福还没到 2024-11-07 10:29:58

Ruby 中没有 &: 运算符。您看到的是 &应用于 :symbol 的运算符。

在方法参数列表中, &运算符获取其操作数,如果尚未将其转换为 Proc 对象(通过对其调用 to_proc),并将其传递给方法,就像使用了块一样。

my_proc = Proc.new { puts "foo" }

my_method_call(&my_proc) # 等同于:
my_method_call { 放置“foo” }

There isn't a &: operator in Ruby. What you are seeing is the & operator applied to a :symbol.

In a method argument list, the & operator takes its operand, converts it to a Proc object if it isn't already (by calling to_proc on it) and passes it to the method as if a block had been used.

my_proc = Proc.new { puts "foo" }

my_method_call(&my_proc) # is identical to:
my_method_call { puts "foo" }

终难遇 2024-11-07 10:29:58

这里的:name是指向标签对象的方法name的符号。
当我们将 &:name 传递给 map 时,它会将 name 视为 proc 对象。
简而言之,tags.map(&:name) 的作用如下:

tags.map do |tag|
  tag.name
end

Here :name is the symbol which point to the method name of tag object.
When we pass &:name to map, it will treat name as a proc object.
For short, tags.map(&:name) acts as:

tags.map do |tag|
  tag.name
end
拥醉 2024-11-07 10:29:58

这意味着

array.each(&:to_sym.to_proc)

it means

array.each(&:to_sym.to_proc)
一梦等七年七年为一梦 2024-11-07 10:29:58

与下面相同:

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

It is same as below:

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end
可遇━不可求 2024-11-07 10:29:57

它是 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

It's shorthand for tags.map(&:name.to_proc).join(' ')

If foo is an object with a to_proc method, then you can pass it to a method as &foo, which will call foo.to_proc and use that as the method's block.

The Symbol#to_proc method was originally added by ActiveSupport but has been integrated into Ruby 1.8.7. This is its implementation:

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end
伴随着你 2024-11-07 10:29:57

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

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(:==))

首选方式应该是最具可读性的方式。

Another cool shorthand, unknown to many, is

array.each(&method(:foo))

which is a shorthand for

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

By calling method(:foo) we took a Method object from self that represents its foo method, and used the & to signify that it has a to_proc method that converts it into a Proc.

This is very useful when you want to do things point-free style. An example is to check if there is any string in an array that is equal to the string "foo". There is the conventional way:

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

And there is the point-free way:

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

The preferred way should be the most readable one.

绝情姑娘 2024-11-07 10:29:57

它相当于

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

It's equivalent to

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end
满栀 2024-11-07 10:29:57
tags.map(&:name)

相同

tags.map{|tag| tag.name}

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

tags.map(&:name)

is The same as

tags.map{|tag| tag.name}

&:name just uses the symbol as the method name to be called.

当梦初醒 2024-11-07 10:29:57

同时我们还要注意,与号 #to_proc 魔法可以用于任何类,而不仅仅是 Symbol。许多 Rubyists 选择在 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!' ) }

While let us also note that ampersand #to_proc magic can work with any class, not just Symbol. Many Rubyists choose to define #to_proc on Array class:

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

# And then...

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

Ampersand & works by sending to_proc message on its operand, which, in the above code, is of Array class. And since I defined #to_proc method on Array, the line becomes:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
输什么也不输骨气 2024-11-07 10:29:57

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

It's shorthand for tags.map { |tag| tag.name }.join(' ')

真心难拥有 2024-11-07 10:29:57

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

正如其他答案中所述,正在调用 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 它期望的块。

Two things are happening here, and it's important to understand both.

As described in other answers, the Symbol#to_proc method is being called.

But the reason to_proc is being called on the symbol is because it's being passed to map as a block argument. Placing & in front of an argument in a method call causes it to be passed this way. This is true for any Ruby method, not just map with symbols.

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)

The Symbol gets converted to a Proc because it's passed in as a block. We can show this by trying to pass a proc to .map without the ampersand:

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"]

Even though it doesn't need to be converted, the method won't know how to use it because it expects a block argument. Passing it with & gives .map the block it expects.

不再见 2024-11-07 10:29:57

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'])< /code> 被执行。

  3. Symbol 类中的 to_proc 过程将发送消息发送到带有参数 (:first) 的数组对象 ([1,'a']),例如 [1,'a' ].send(:first) 被执行。

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

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

Josh Lee's answer is almost correct except that the equivalent Ruby code should have been as follows.

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

With this code, when print [[1,'a'],[2,'b'],[3,'c']].map(&:first) is executed, Ruby splits the first input [1,'a'] into 1 and 'a' to give obj 1 and args* 'a' to cause an error as Fixnum object 1 does not have the method self (which is :first).


When [[1,'a'],[2,'b'],[3,'c']].map(&:first) is executed;

  1. :first is a Symbol object, so when &:first is given to a map method as a parameter, Symbol#to_proc is invoked.

  2. map sends call message to :first.to_proc with parameter [1,'a'], e.g., :first.to_proc.call([1,'a']) is executed.

  3. to_proc procedure in Symbol class sends a send message to an array object ([1,'a']) with parameter (:first), e.g., [1,'a'].send(:first) is executed.

  4. iterates over the rest of the elements in [[1,'a'],[2,'b'],[3,'c']] object.

This is the same as executing [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) expression.

爱殇璃 2024-11-07 10:29:57

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

to_proc 实际上是用 C 实现的

(&:name) is short for (&:name.to_proc) it is same as tags.map{ |t| t.name }.join(' ')

to_proc is actually implemented in C

我是男神闪亮亮 2024-11-07 10:29:57

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

简写

array.map { |element| element.name }

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

map(&:name) takes an enumerable object (tags in your case) and runs the name method for each element/tag, outputting each returned value from the method.

It is a shorthand for

array.map { |element| element.name }

which returns the array of element(tag) names

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文