2013-02-14 11 views
31

Rayları öğreniyorum ve this thread'u takip ediyorum. to_proc yöntemiyle takılıyorum. Sembolleri sadece iplere alternatif olarak düşünürüm (onlar dizgeye benziyorlar ama bellek bakımından daha ucuzlar). Simgeler için başka bir şey varsa, lütfen bana söyleyin. Lütfen to_proc'un ne anlama geldiğini ve ne için kullanıldığını basit bir şekilde açıklayınız.to_proc yöntemi ne anlama geliyor?

cevap

77

Bazı yöntemler bir blok almak ve bu desen sık bir blok için görünür:

{|x| x.foo} 

ve insanlar daha özlü bir şekilde o yazmak istiyorum. Bunu yapmak için, bir sembol, Symbol#to_proc, örtük sınıf döküm yöntemi ve & operatörü birlikte kullanılır. Bağımsız değişken konumuna Proc örneğinin önüne & koyarsanız, bu bir blok olarak yorumlanır. Proc örneğinden & ile başka bir şey birleştirirseniz, örtük sınıf döküm, varsa to_proc yöntemini kullanarak Proc örneğini dönüştürmeyi deneyecektir. Bir Symbol örneği durumunda, bu yolla to_proc çalışır: Örneğin

:foo.to_proC# => ->x{x.foo} 

, bu gibi yazmak varsayalım:

& operatörü Proc örneği olmadığı, :foo ile birleştirilir
bar(&:foo) 

Bu nedenle, örtük sınıfsal döküm Symbol#to_proc değerini uygular, bu da ->x{x.foo} değerini verir. & şimdi bu geçerli olduğu ve veren bir blok olarak yorumlanır: Bu bir örnek vermektir açıklamaya

bar{|x| x.foo} 
+3

açıklama +1 :) – swapnesh

+0

Plus için teşekkürler, buna göre , 20 çalışma zamanı boyunca daha hızlı. –

+0

Anladım & proc bir blok veriyor, & x' sonuçta x oluyor ve sonra her şey bir blok veriyor. Ayrıca, Symbol'un to_proc yöntemine sahip olduğunu anlıyorum. Ancak anlamadığım ve bu cevabın eksik olduğunu hissettiğim kısım, sembol ve yöntemlerin nasıl bağlandığıdır. Yani tüm yöntemler aynı zamanda –

39

kolay yolu.

(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"] 

ve

[1,2,3].collect(&:succ) #=> [2, 3, 4] 

aynı mı:
(1..3).collect(&:to_s) #=> ["1", "2", "3"] 

aynı mı verilen yönteme yanıt veren bir Proc nesnesi geri to_proc

[1,2,3].collect {|num| num.succ} #=> [2, 3, 4] 

sembol tarafından. Üçüncü durumda, dizi [1,2,3] toplama yöntemini çağırır ve. succ, Array sınıfı tarafından tanımlanan yöntemdir. Dolayısıyla bu parametre, dizideki her bir elemanı toplamak ve ardılını iade etmenin kısa bir yoludur ve bundan [2,3,4] ile sonuçlanan yeni bir dizi yaratır. Sembol: succ bir Proc nesnesine dönüştürülür, böylece Array'ın succ yöntemini çağırır.

+3

@Dilon +1 örnekler için :) – swapnesh

7

Benim için en açık açıklama, basit bir uygulama olduğunu görmektir.biraz daha net Birileri

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' 
+1

Bu! Bu arada, 'Symbol' sınıfında maymun yama yapmaya çalıştığınız yöntemde 'my_to_proc' olmamalıdır? –

+0

@AgungSetiawan İyi yakalama! Bunun yerine, aramayı my_to_proc yerine toproc çağrısı yapmak için yeniden adlandırdım. –

1

hala biraz stumped, aşağıdaki kodu çalıştıran şeyler hale getirebileceğini:

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}" 

Bunlar olmadığında İşte ben reimplementing olsaydı gibi Sembol # to_proc göründüğü aşağıda Symbol.to_proc veya Array.map'un gerçek uygulamaları, sadece map &:to_s ve benzeri çağrıların nasıl çalıştığını göstermek için kullanıyorum basitleştirilmiş sürümleridir.