web-dev-qa-db-ja.com

Rubyでmap(&:name)はどういう意味ですか?

このコードは a RailsCast にあります。

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

map(&:name)(&:name)はどういう意味ですか?

476
collimarco

tags.map(&:name.to_proc).join(' ')の省略形です

footo_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
500
Josh Lee

多くの人に知られていない、もう一つのクールな速記は、

array.each(&method(:foo))

これはの省略形です

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

method(:foo)を呼び出すことによって、そのMethodメソッドを表すselfからfooオブジェクトを取得し、それをProcに変換する&method があることを示すためにto_procを使用しました。

ポイントフリースタイルを使いたいときにとても便利です。例として、文字列"foo"と等しい文字列が配列内にあるかどうかを確認することがあります。従来の方法があります。

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

そして、ポイントフリーの方法があります。

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

好ましい方法は、最も読みやすい方法です。

166
Gerry

それと同等です

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

また、アンパーサンドの#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!"]

Ampersand &は、そのオペランドにto_procメッセージを送信することによって機能します。上記のコードでは、これはArrayクラスです。そして、私は#to_procメソッドをArrayに定義したので、その行は次のようになります。

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
42
Boris Stitnicky

tags.map { |tag| tag.name }.join(' ')の省略形です

37
Oliver N.
tags.map(&:name)

と同じ

tags.map{|tag| tag.name}

&:nameは、呼び出されるメソッド名としてシンボルを使用するだけです。

31
Albert.Qing

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)が実行されると、最初の入力[1,'a']を1と 'a'に分割してobj 1とargs* 'aを指定し、Fixnumオブジェクト1にはselfというメソッドがないため、エラーが発生します。 。


[[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'])が実行されます。

  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)式を実行するのと同じです。

14
prosseek

ここで2つのことが起こっています、そして両方を理解することは重要です。

他の回答で説明されているように、Symbol#to_procメソッドが呼び出されています。

しかし、シンボルに対してto_procが呼び出されるのは、ブロック引数としてmapに渡されるためです。メソッド呼び出しの引数の前に&を配置すると、このように渡されます。これは、シンボル付きのmapだけでなく、あらゆるRubyメソッドに当てはまります。

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に期待するブロックが与えられます。

11
devpuppy

(&:name)は(&:name.to_proc)の省略形です。tags.map{ |t| t.name }.join(' ')と同じです。

to_procは実際にはCで実装されています

5
tessie

map(&:name)は列挙可能なオブジェクト(あなたの場合はタグ)を取り、各要素/タグに対してnameメソッドを実行し、そのメソッドから返されたそれぞれの値を出力します。

それはの省略形です

array.map { |element| element.name }

これは要素(タグ)名の配列を返します

2
Sunda

初心者の視点から見て、私たちはすでにすばらしい答えを持っていますが、私は追加情報を加えたいと思います:

Rubyでmap(&:name)はどういう意味ですか?

これはつまり、マップ関数のパラメータとして別のメソッドを渡しているということです。 (実際には、procに変換されるシンボルを渡します。ただし、この場合はこれは重要ではありません)。

重要なことは、methodという名前のnameがあり、これが従来のblockスタイルの代わりに引数としてmapメソッドによって使用されることです。

2
Jonathan Duarte

ここで:nameはtagオブジェクトのメソッドnameを指すシンボルです。 &:namemapに渡すと、nameをprocオブジェクトとして扱います。手短に言うと、tags.map(&:name)は次のように動作します。

tags.map do |tag|
  tag.name
end
1
timlentse

その意味は

array.each(&:to_sym.to_proc)
1
mminski

以下と同じです。

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

基本的に、配列内の各タグに対してメソッド呼び出しtag.nameを実行します。

これは単純化されたRubyの省略形です。

0