536

RailsCastでこのコードを見つけました:

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

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

4

16 に答える 16

535

の略です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
于 2009-08-01T17:50:37.423 に答える
190

多くの人に知られていないもう 1 つのクールな省略形は、次のとおりです。

array.each(&method(:foo))

これはの省略形です

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

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

これは、ポイントフリースタイルで物事を行いたい場合に非常に便利です。例として、配列内に string と等しい文字列があるかどうかを確認します"foo"。従来の方法があります:

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

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

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

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

于 2012-03-08T18:07:09.230 に答える
80

と同等です

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end
于 2009-08-01T17:39:52.267 に答える
50

#to_procまた、アンパサンドマジックは、Symbol だけでなく、どのクラスでも機能することに注意してください。多くの Rubyist#to_procは Array クラスで定義することを選択します:

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

# And then...

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

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

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
于 2012-11-20T12:38:28.233 に答える
41

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

于 2009-08-01T17:37:34.033 に答える
16

ここでは 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、期待するブロックが得られます。

于 2016-04-09T01:43:55.403 に答える
5

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

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

于 2016-08-25T05:50:15.210 に答える
1

タグオブジェクト:nameのメソッドを指すシンボルを次に示します。nameに渡す&:nameと、proc オブジェクトとしてmap扱われます。name要するに、次のようにtags.map(&:name)機能します。

tags.map do |tag|
  tag.name
end
于 2016-06-30T06:30:44.097 に答える
-1

以下と同じです。

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end
于 2016-06-27T09:32:18.873 に答える