Sự khác nhau giữa Block, Proc, và Lamdba trong Ruby
Bài đăng này đã không được cập nhật trong 7 năm
Block, Proc, và Lamdba là gì ?
- Theo định nghĩa kỹ thuật: thì nó là ví dụ của closures trong Ruby. Có thể hiểu
closures
là một hàm được tạo ra từ bên trong một hàm khác (hàm cha), và nó có thể sử dụng các biến toàn cục, cục bộ của hàm cha và chính nó. Viết code kiểuclosures
có thể giúp code dễ quản lý hơn và linh hoạt hơn trong việc xử lý. - Theo định nghĩa đơn giản: thì nó là cách để chúng ta nhóm các đoạn mã muốn chạy vào một khối.
# Block
[1,2,3].each { |x| puts x*2 } # block nằm trong dấu ngoặc nhọn
[1,2,3].each do |x|
puts x*2 # block cũng có thể nằm giữa do và end
end
# Proc
p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p) # & sẽ nói với Ruby là đưa proc vào một block
proc = Proc.new { puts "Hello World" }
proc.call # bên trong của object Proc sẽ được thực thi khi sử dụng call
# Lambda
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)
lam = lambda { puts "Hello World" }
lam.call
Qua ví dụ trên, ta có thể thấy chúng khá là giống nhau và đơn giản, nhưng vẫn có sự khác nhau. Hãy cùng tìm hiểu phía dưới.
Khác nhau giữa Blocks và Procs
- Procs là đối tượng, còn Block thì không
Proc là một instance của class Proc
p = Proc.new { puts "Hello World" }
p.call # prints 'Hello World'
p.class # returns 'Proc'
a = p # a now equals p, a Proc instance
p # returns a proc object '#<Proc:0x007f96b1a60eb0@(irb):46>'
Ngược lại, một block chỉ là một phần của cú pháp trong method được gọi. Nó không đứng một mình được mà chỉ có thể đi cùng một list các đối số
{ puts "Hello World"} # syntax error
a = { puts "Hello World"} # syntax error
[1,2,3].each {|x| puts x*2} # chỉ làm việc như một phần cú phép của method được gọi
- Có thể truyền nhiều procs vào method
Vì proc
là một đối tượng độc lập vì vậy ta có thể truyền nhiều procs như một tham số vào method. Còn block
thì giới hạn hơn nhiều, nó chỉ có thể hoạt động khi đi kèm một list các đối số.
def multiple_procs(proc1, proc2)
proc1.call
proc2.call
end
a = Proc.new { puts "First proc" }
b = Proc.new { puts "Second proc" }
multiple_procs(a,b)
Khác nhau giữa Procs và Lambdas
Cả Procs
và Lambdas
đều là đối tượng của class Proc
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }
proc.class # returns 'Proc'
lam.class # returns 'Proc'
Tuy nhiên, chúng lại có một sự khác biệt nhỏ.
proc # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'
Sự khác biệt đấy là:
Lambdas
kiểm tra số lượng đối số, trong khiprocs
thì không
lam = lambda { |x| puts x } # tạo lambda với một đối số
lam.call(2) # in ra 2
lam.call # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3) # ArgumentError: wrong number of arguments (3 for 1)
proc = Proc.new { |x| puts x } # tạo proc với một đối số
proc.call(2) # in ra 2
proc.call # returns nil
proc.call(1,2,3) # in ra 1, và 2 đối số còn lại sẽ bị bỏ qua
Lambdas
vàProcs
xử lýreturn
khác nhaureturn
được viết tronglambda
sẽ chỉ có tác động outside khỏi lambda code
def lambda_test
lam = lambda { return }
lam.call
puts "Hello world"
end
lambda_test # lambda_test sẽ vẫn in ra 'Hello World'
return
được viết trong proc
sẽ tác động outside luôn method tại điểm proc
được thực thi
def proc_test
proc = Proc.new { return }
proc.call
puts "Hello world"
end
proc_test # proc_test sẽ không in ra gì cả
All rights reserved