Ve birini diğerinden ziyade ne zaman kullanırsınız?
Ve birini diğerinden ziyade ne zaman kullanırsınız?
Yanıtlar:
Farklardan biri, argümanları ele alma biçimidir. Kullanarak bir proc oluşturma proc {}ve Proc.new {}eşdeğerdir. Ancak, kullanmak lambda {}size iletilen bağımsız değişken sayısını kontrol eden bir proc sağlar. Gönderen ri Kernel#lambda:
Eşdeğer Proc.new elde edilen Proc hariç çağrıldığında geçen parametre sayısını kontrol nesneleri.
Bir örnek:
p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)
Buna ek olarak, Ken'nin işaret ettiği gibi, returnbir lambda içinde kullanmak bu lambda'nın değerini döndürür, ancak returnbir proc'da kullanmak kapalı bloktan döner.
lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return
Bu nedenle, çoğu hızlı kullanım için aynıdırlar, ancak otomatik katı bağımsız değişken denetimi (bazen hata ayıklamaya da yardımcı olabilir) veya returnproc'un değerini döndürmek için ifadeyi kullanmanız gerekiyorsa kullanın lambda.
Procs ve lambdas arasındaki gerçek fark, kontrol akışı anahtar kelimeleriyle ilgilidir. Ancak bahsettiğimiz return, raise, break, redo, retrybu kontrol kelimeleri - vs.. Diyelim ki bir süreçte iade beyanınız var. Proc'unuzu çağırdığınızda, sadece sizi dışarı atmaz, aynı zamanda ek yöntemden de geri döner:
def my_method
puts "before proc"
my_proc = Proc.new do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
putsYöntemin finali asla yürütülmedi, çünkü proc'umuzu çağırdığımızda, içerideki returnyöntemden bizi terk etti. Bununla birlikte, proc'umuzu bir lambda'ya dönüştürürsek, aşağıdakileri elde ederiz:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
Lambda içindeki dönüş bizi sadece lambda'nın dışına atar ve kapatma yöntemi çalışmaya devam eder. Kontrol akışı anahtar kelimelerinin proc ve lambdalar içinde işlenme şekli aralarındaki temel farktır
Sadece iki ana fark vardır.
lambdailetilen bağımsız değişkenlerin sayısını denetlerken , a procdeğil. Bu, a lambdaifadesinin yanlış sayıda argüman iletmeniz durumunda bir hata atar, oysa a procbeklenmeyen argümanları yoksayar ve nileksik olanlara atar .lambdageri döndüğünde kontrolü çağıran yönteme geri aktarır; bir procgeri döndüğünde, arama yöntemine geri dönmeden bunu hemen yapar.Bunun nasıl çalıştığını görmek için aşağıdaki koda bir göz atın. İlk yöntemimiz proc; ikinci çağrı a lambda.
def batman_ironman_proc
victor = Proc.new { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_proc # prints "Batman will win!"
def batman_ironman_lambda
victor = lambda { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_lambda # prints "Iron Man will win!"
Bakın proc"Batman kazanacak!" Diyor, bunun nedeni batman_ironman_proc yöntemine geri dönmeden hemen geri dönmesidir.
lambdaAncak bizim çağrıldıktan sonra yönteme geri döner, böylece yöntem değerlendirdiği son kodu döndürür: "Iron Man kazanacak!"
# Proc Örnekleri
p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p) # The '&' tells ruby to turn the proc into a block
proc = Proc.new { puts "Hello World" }
proc.call
# Lambda Örnekleri
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)
lam = lambda { puts "Hello World" }
lam.call
Procs ve Lambdas arasındaki farklar
Procs ve lambdalar arasındaki farklara girmeden önce, her ikisinin de Proc nesnesi olduğunu belirtmek önemlidir.
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }
proc.class # returns 'Proc'
lam.class # returns 'Proc'
Ancak lambdalar, farklı bir procs lezzetidir. Bu küçük fark, nesneleri döndürürken gösterilir.
proc # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'
1. Lambdas argüman sayısını kontrol ederken proclar
lam = lambda { |x| puts x } # creates a lambda that takes 1 argument
lam.call(2) # prints out 2
lam.call # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3) # ArgumentError: wrong number of arguments (3 for 1)
Aksine, procslar yanlış sayıda argümanın geçip geçmediği umurumda değil.
proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2) # prints out 2
proc.call # returns nil
proc.call(1,2,3) # prints out 1 and forgets about the extra arguments
2. Lambdas ve procs 'return' anahtar kelimesine farklı davranıyor
Bir lambda'nın içindeki 'dönüş' kodu, lambda kodunun hemen dışındaki kodu tetikler
def lambda_test
lam = lambda { return }
lam.call
puts "Hello world"
end
lambda_test # calling lambda_test prints 'Hello World'
Bir proc'un içindeki 'return', proc'un yürütüldüğü yöntemin dışındaki kodu tetikler
def proc_test
proc = Proc.new { return }
proc.call
puts "Hello world"
end
proc_test # calling proc_test prints nothing
Ve diğer sorgunuzu cevaplamak için hangisini ne zaman kullanmalı? Bahsettiği gibi @jtbandes'i takip edeceğim
Bu nedenle, çoğu hızlı kullanım için aynıdırlar, ancak otomatik katı bağımsız değişken denetimi istiyorsanız (bu da bazen hata ayıklamaya yardımcı olabilir) veya proc değerini döndürmek için return deyimini kullanmanız gerekiyorsa lambda kullanın.
Başlangıçta buraya gönderildi
Genel olarak konuşursak, lambdalar prokilerden daha sezgiseldir çünkü yöntemlere daha benzerler. Arity konusunda oldukça katılar ve dönüşü çağırdığınızda çıkarlar. Bu nedenle, birçok Rubyist, procların belirli özelliklerine ihtiyaç duymadıkları sürece lambdas'ı ilk seçenek olarak kullanır.
Procs: Sınıf nesneleri Proc. Bloklar gibi, tanımlandıkları kapsamda değerlendirilirler.
Lambdas: Ayrıca sınıftaki nesneler, Procama normal süreçlerden oldukça farklı. Bloklar ve proclar gibi kapaklardır ve bu nedenle tanımlandıkları kapsamda değerlendirilirler.
Proc Oluşturma
a = Proc.new { |x| x 2 }
Lambda oluşturma
b = lambda { |x| x 2 }
a = proc { |x| x 2 }ile aynıa = Proc.new { |x| x 2 }
İşte bunu anlamanın başka bir yolu.
Blok, bir nesne üzerindeki bir yöntemin çağrılması için çağrılan bir kod dizisidir. Aşağıdaki örnekte self, Rails çerçevesinde ActionView :: Base'den devralınan anonim bir sınıfın bir örneğidir (kendisi birçok yardımcı modülü içerir). Kart, kendi üzerine dediğimiz bir yöntemdir. Yönteme bir argüman iletiriz ve sonra bloğu her zaman yöntem çağrısının sonuna ekleriz:
self.card :contacts do |c|
// a chunk of valid ruby code
end
Pekala, bir yönteme kod yığınını geçiriyoruz. Fakat bu bloğu nasıl kullanacağız? Bir seçenek, kod yığınını bir nesneye dönüştürmektir. Ruby, bir kod parçasını bir nesneye dönüştürmenin üç yolunu sunar
# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2
# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2
# & as the last method argument with a local variable name
def add(&block)
end
Yukarıdaki yöntemde, & yönteme iletilen bloğu bir nesneye dönüştürür ve o nesneyi yerel değişken bloğunda saklar. Aslında, lambda ve Proc ile aynı davranışa sahip olduğunu gösterebiliriz. Yeni:
def add(&block)
block
end
l3 = add { |a| a + 1 }
l3.call(1)
=> 2
Bu önemli. Bir bloğu bir yönteme geçirip & öğesini kullanarak dönüştürdüğünüzde, oluşturduğu nesne dönüştürme işlemi için Proc.new öğesini kullanır.
Ben bir seçenek olarak "proc" kullanmaktan kaçındım unutmayın. Çünkü Ruby 1.8, lambda ile aynıdır ve Ruby 1.9'da Proc.new ile aynıdır ve tüm Ruby versiyonlarında kaçınılmalıdır.
Öyleyse lambda ve Proc.new arasındaki farkın ne olduğunu soruyorsunuz?
İlk olarak, parametre geçişi açısından lambda bir yöntem çağrısı gibi davranır. Yanlış sayıda argüman iletirseniz bir istisna ortaya çıkar. Aksine, Proc.new paralel atama gibi davranır. Kullanılmayan tüm argümanlar nil değerine dönüştürülür:
> l = lambda {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb47e40@(irb):19 (lambda)>
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)
> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0@(irb):21>
> l2.call(1)
1 +
İkincisi, lambda ve Proc.new, return anahtar sözcüğünü farklı şekilde ele alır. Proc.new içinde bir dönüş yaptığınızda, aslında çevreleme yönteminden, yani çevreleyen bağlamdan döner. Bir lambda bloğundan döndüğünüzde, kapalı yöntemden değil, yalnızca bloktan döner. Temel olarak, çağrıdan bloğa çıkar ve kapatma yönteminin geri kalanıyla yürütmeye devam eder.
> def add(a,b)
l = Proc.new { return a + b}
l.call
puts "now exiting method"
end
> add(1,1)
=> 2 # NOTICE it never prints the message "now exiting method"
> def add(a,b)
l = lambda { return a + b }
l.call
puts "now exiting method"
end
> add(1,1)
=> now exiting method # NOTICE this time it prints the message "now exiting method"
Öyleyse neden bu davranış farkı? Bunun nedeni Proc.new ile yineleyicileri kapalı yöntemler bağlamında kullanabilir ve mantıksal sonuçlar çıkarabiliriz. Şu örneğe bakın:
> def print(max)
[1,2,3,4,5].each do |val|
puts val
return if val > max
end
end
> print(3)
1
2
3
4
Yineleyicinin içindeki dönüşü çağırdığımızda, çevirme yönteminden döneceğini umuyoruz. Yineleyicilere iletilen blokların Proc.new kullanarak nesnelere dönüştürüldüğünü ve bu nedenle return kullandığımızda, kapatma yönteminden çıkacağını unutmayın.
Lambdaları anonim yöntemler olarak düşünebilirsiniz, tek tek kod bloklarını bir yöntem gibi ele alınabilecek bir nesneye ayırırlar. Sonuçta, bir lambda'yı anomyous bir yöntem olarak ve Proc. Yeni satır içi kod olarak davranmayı düşünün.
Ruby kılavuzları hakkında yararlı bir yazı: bloklar, procs ve lambdas
Protezler mevcut yöntemden, lambdalar ise lambda'nın kendisinden döner.
Protezler doğru sayıda argümanı umursamazken, lambdalar bir istisna doğuracak.
returniçinde gelen deyim getirilerprockarşılambda.