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

我在RailsCast中找到了以下代码:

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

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


#1楼

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


#2楼

相当于

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

#3楼

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

#4楼

同时让我们注意到,&符#to_proc魔术可以与任何类一起使用,而不仅限于Symbol。 许多Ruby #to_proc选择在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!' ) }

#5楼

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通过参数[1,'a']向:first.to_proc发送呼叫消息,例如,执行:first.to_proc.call([1,'a'])

  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)表达式相同。


#6楼

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

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


#7楼

如下:

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

#8楼

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

tags.map do |tag|
  tag.name
end

#9楼

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

to_proc实际上是用C实现的


#10楼

tags.map(&:name)

是相同的

tags.map{|tag| tag.name}

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


#11楼

它的意思是

array.each(&:to_sym.to_proc)

#12楼

尽管我们已经有了不错的答案,但是从初学者的角度来看,我想添加其他信息:

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

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

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


#13楼

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

这是

array.map { |element| element.name }

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


#14楼

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

这是简化的红宝石速记。


#15楼

许多人不知道的另一个很酷的速记是

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

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

发布了0 篇原创文章 · 获赞 2 · 访问量 4985

猜你喜欢

转载自blog.csdn.net/asdfgh0077/article/details/104031201