+1

Khác biệt giữa Block, Proc và Lambda trong Ruby

Block, Proc và Lambda là gì?

Block, proc và lambda là một trong những đặc điểm rất hay của Ruby. Nói đơn giản thì nó là một cách để tập hợp một hay nhiều dòng code được đặt trong 2 dấu ngoặc nhọn { } hoặc do...end. Convention chung là nếu chỉ có 1 dòng code thì đặt trong { }, còn nhiều hơn 2 dòng thì ta đặt nó trong do...end. Chúng thường được kết hợp với những methods như each, map để thực thi một việc nào đó cho từng element trong một hash hoặc array. Ví dụ:

  • Block
 [1, 2, 3].each {|x| puts x} 
 [1, 2, 3].each do |x|
   x += 6
   puts x
 end
  • Proc
p = Proc.new {|x| puts x} # tạo 1 đối tượng Proc
[1, 2, 3].each(&p) # dấu & giúp chuyển p thành block để truyền vào each

p = Proc.new {puts "Dota 2"}
p.call # thực thi đoạn code nằm trong body của p
  • Lambda
l = lambda {|x| puts x}
[1, 2, 3].each(&l)

l = lambda {puts "Dota 2"}
l.call

Từ những ví dụ trên ta có thể thấy block, proc và lambda về cơ bản rất giống nhau, tuy nhiên giữa chúng vẫn có 1 số khác biệt cần lưu ý.

Khác biệt giữa block, proc và lambda

Giữa block và proc

Proc là object còn block thì không p = Proc.new {puts "Dota 2"} thì p là một instance của class Proc, chúng ta có thể gọi method trên nó và cũng có thể gán nó vào 1 biến. Ví dụ:

p.call => "Dota 2"
p.class => "Proc"

Ngược lại với Proc, block không phải là object, nó chỉ là 1 đoạn code được đặt trong { } hoặc do...end thôi, bản thân nó vốn không có nghĩa gì cả, và nó chỉ có thể được truyền như một đối số. Ví dụ:

{puts "Dota 2"} => lỗi cú pháp
a = {puts "Dota 2"} => lỗi cú pháp
[1, 2, 3].each {|x| print x} => 123

Giữa Proc và Lambda

Proc và Lambda rất giống nhau, bởi vì chúng đều là Proc object.

p = Proc.new {puts "Dota 2"}
l = lambda {puts "Dota 2"}

p.class => Proc
l.class => Proc

Giữa chúng chỉ có 2 sự khác biệt chính như sau:

  1. Lambda kiểm tra số đối số truyền vào trong khi proc thì không. Có nghĩa là lambda sẽ throw error nếu số đối số truyền vào nó không đúng còn proc sẽ bỏ qua những đối số dư và gán nil cho những đối số bị thiếu
    p = Proc.new {|x| puts x}
    p.call("Dota 2") => "Dota 2"
    p.call => nil
    p.call("Dota 2", "Hello") => "Dota 2"
    
    l = lambda {|x| puts x}
    l.call("Dota 2") => "Dota 2"
    l.call => ArgumentError: wrong number of arguments (0 for 1)
    l.call("Dota 2", "Hello") => ArgumentError: wrong number of arguments (2 for 1)
  1. Giả sử proc và lambda được gọi trong một method nào đó, return ở trong lambda sẽ pass control về cho method gọi nó, còn proc thì sẽ return ngay lập tức mà không quay lại method đó Ví dụ:
    def test_lambda
        l = lambda {return}
        l.call
        puts "Dota 2"
   end
   test_lambda => return sẽ quay về method test_lambda và tiếp tục thực thi phía dưới, kết quả ra "Dota 2"
   
   def test_proc
       p = Proc.new{return}
       p.call
       puts "Dota 2"
   end
   test_proc => return sẽ lập tức ra khỏi method test_proc, kết quả là không có gì cả

Kết luận

  1. Proc, lambda là object, block thì không
  2. Lambda kiểm tra số đối số, proc thì không
  3. Lambda và proc khi gặp return có cách xử lí khác nhau

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí