私はRailsとそれに続く このスレッド を学んでいます。to_proc
方法。シンボルは文字列の代替としてのみ考えます(文字列に似ていますが、メモリの点では安価です)。シンボルに不足しているものがあれば、教えてください。 to_proc
は、それが何に使用されるかを意味します。
一部のメソッドはブロックを取得し、ブロックに対してこのパターンが頻繁に表示されます。
{|x| x.foo}
人々はより簡潔な方法でそれを書きたいと思っています。これを行うには、シンボル、メソッドSymbol#to_proc
、暗黙的なクラスキャスト、および&
演算子を組み合わせて使用します。引数の位置でProc
インスタンスの前に&
を置くと、ブロックとして解釈されます。 Proc
インスタンス以外の何かを&
と組み合わせると、暗黙的なクラスキャストは、そのオブジェクトで定義されたto_proc
メソッドを使用して、それをProc
インスタンスに変換しようとします。ある場合。 Symbol
インスタンスの場合、to_proc
は次のように機能します。
:foo.to_proc # => ->x{x.foo}
たとえば、次のように書くと仮定します。
bar(&:foo)
&
演算子は、Proc
インスタンスではない:foo
と結合されるため、暗黙のクラスキャストはSymbol#to_proc
を適用し、->x{x.foo}
を提供します。 &
がこれに適用され、ブロックとして解釈されます:
bar{|x| x.foo}
これを説明する最も簡単な方法は、いくつかの例を使用することです。
(1..3).collect(&:to_s) #=> ["1", "2", "3"]
次と同じです:
(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"]
そして
[1,2,3].collect(&:succ) #=> [2, 3, 4]
次と同じです:
[1,2,3].collect {|num| num.succ} #=> [2, 3, 4]
to_procは、指定されたメソッドにシンボルで応答するProcオブジェクトを返します。したがって、3番目の場合、配列[1,2,3]はそのcollectメソッドを呼び出します。 succは、Arrayクラスによって定義されたメソッドです。したがって、このパラメーターは、配列内の各要素を収集し、その後継を返し、それから新しい配列を作成して[2,3,4]を生成するという簡単な方法です。シンボル:succはProcオブジェクトに変換されているため、配列のsuccメソッドを呼び出します。
私にとって最も明確な説明は、それの簡単な実装を見ることです。 Symbol#to_procを再実装すると、次のようになります。
class Symbol # reopen Symbol class to reimplement to_proc method
def to_proc
->(object) { object.send(self) }
end
end
my_lambda = :to_s.to_proc
puts my_lambda.(1) # prints '1'; .() does the same thing as .call()
puts my_lambda.(1).class # prints 'String'
puts [4,5,6].map(&:to_s) # prints "4\n5\n6\n"
puts [4,5,6].map(&:to_s).first.class # prints 'String'
まだ少し困惑している人のために、次のコードを実行すると少しわかりやすくなります。
class Symbol
def to_proc
proc do |obj|
puts "Symbol proc: #{obj}.send(:#{self})"
obj.send(self)
end
end
end
class Array
def map(&block)
copy = self.class.new
self.each do |index|
puts "Array.map: copy << block.call(#{index})"
copy << block.call(index)
end
copy
end
end
remapped_array = [0, 1, 2].map &:to_s
puts "remapped array: #{remapped_array.inspect}"
これらはSymbol.to_proc
またはArray.map
の実際の実装ではなく、map &:to_s
および同様の呼び出しがどのように機能するかを示すために使用している単純化されたバージョンです。