RailsCastでこのコードを見つけました:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
何を(&:name)
してmap(&:name)
意味ですか?
RailsCastでこのコードを見つけました:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
何を(&:name)
してmap(&:name)
意味ですか?
回答:
それは略記です 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
&
。つまり、tags.map(&:name.to_proc).join(' ')
多くの人には知られていない別のクールな速記法は
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))
アンパサンド#to_proc
マジックは、シンボルだけでなく、どのクラスでも機能することにも注意してください。多くの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!' ) }
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としてエラーを引き起こします。
いつ[[1,'a'],[2,'b'],[3,'c']].map(&:first)
実行されるか
:first
Symbolオブジェクトであるため&:first
、mapメソッドにパラメーターとして指定すると、Symbol#to_procが呼び出されます。
mapは:first.to_procにパラメータを指定して呼び出しメッセージを送信します[1,'a']
。たとえば、:first.to_proc.call([1,'a'])
実行されます。
Symbolクラスのto_procプロシージャは、実行メッセージなどの[1,'a']
パラメータ(:first)を使用して、配列オブジェクト()に送信メッセージを送信します[1,'a'].send(:first)
。
[[1,'a'],[2,'b'],[3,'c']]
オブジェクトの残りの要素を反復処理します。
これは[[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
式の実行と同じです。
[1,2,3,4,5,6].inject(&:+)
-注入の2つのパラメータ(メモやアイテム)とラムダを期待し、:+.to_proc
それを実現- Proc.new |obj, *args| { obj.send(self, *args) }
または{ |m, o| m.+(o) }
ここでは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
、それがブロックとして渡されているため。.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
、期待するブロックが得られます。
すでにすばらしい回答はありますが、初心者の視点から見て、追加情報を追加したいと思います。
Rubyでmap(&:name)はどういう意味ですか?
これは、map関数にパラメーターとして別のメソッドを渡すことを意味します。(実際には、procに変換されるシンボルを渡します。しかし、これはこの特定のケースではそれほど重要ではありません)。
重要なのは、従来のスタイルの代わりに引数としてマップメソッドで使用されるmethod
名前が付いname
ていることblock
です。