Thành thạo Ruby Block trong 5 phút

Block trong ngôn ngữ ruby là gì?

Về cơ bản, block trong ruby là đoạn code nằm giữa doend 😄.

Chúng ta có hai cách viết block:

  • Viết thành nhiều dòng, viết giữa doend
  • Viết 1 dòng, viết giữa hai dấu {}

Cả hai cách đều cho ra một kết quả giống nhau, nhưng khi dòng code của bạn quá dài thì nên lựa chọn cách viết thứ 2, bởi nó giúp code của dễ đọc hơn 😄.

Ví dụ :

Khi viết code nhiều dòng

[1, 2, 3].each do |n|
  puts "Number #{n}"
end

Có thể viết thành một dòng như:

[1, 2, 3].each {|n| puts "Number #{n}"}

|n| được gọi là tham số block (block parameter), giá trị của nó trong trường hợp này được gọi lần lượt theo giá trị của mảng đã cho, đầu tiên nhận giá trị là 1, lần thứ 2 là 2, cuối cùng là 3

Kết quả:

Number 1
Number 2
Number 3
 => [1, 2, 3]

yield làm việc như nào ?

yield là một phần sức mạnh của ruby block, nó chịu trách nhiệm về mọi sự ảo diệu cũng như nhầm lẫn trong block. Phần lớn sự nhầm lẫn đều đến từ cách gọi block và việc làm thế nào để truyền tham số vào trong nó

Chúng ta hãy xem ví dụ sau:

def my_method
  puts "reached the top"
  yield
  puts "reached the bottom"
end

my_method do
  puts "reached yield"
end

Kết quả:

reached the top
reached yield
reached the bottom
 => nil

Về cơ bản, khi bạn thực thi my_method và đến dòng gọi đến yield, nó sẽ chuyển đến gọi block truyền tham số. Sau đoạn code bên trong block chạy xong, nó sẽ lại tiếp tục chạy code trong hàm my_method tiếp

Một điều lưu ý ở đây là các tham số bên trong block là cục bộ đối với block (không giống như các tham số được truyền từ phương thức vào block).

Đưa vào yield nhiều tham số

Bất kỳ tham số nào được truyền cho yield sẽ đóng vai trò là tham số của một block. Vì vậy, khi block chạy, nó có thể sử dụng các tham số được truyền từ phương thức ban đầu. Các tham số này có thể trở thành biến địa phương (variables local) đối với phương thức trong yield

Thứ tự của các đối số truyền vào cũng rất quan trọng bởi vì thứ tự bạn sắp xếp cũng là thứ tự mà phương thức đó nhận được nó

Ý nghĩa của &block

Bạn có thể nhìn thấy &block được xuất hiện rất nhiều nơi trong các đoạn code của ruby. Đây là cách bạn có thẻ tham chiếu đến block (thay vì sử dụng biến địa phương) cho một phương thức. Trên thực tế, ruby cho phép bạn truyền bất kỳ đối tượng nào thành phương thức như thể nó là một block. Phương thức sẽ cố gắng đưa đội tượng về dạng block, nhưng nếu nó không phải dạng block sẽ gọi to_proc vào trong để chuyển đổi nó về dạng block

def my_method(&block)
  puts block
  block.call
end

my_method { puts "Hello!" }

Kết quả:

#<Proc:[email protected]/example.rb:6>
Hello!

Biến block bên trong phương thức my_method là một tham chiếu đến block và nó có thể thực hiện bằng phương thức call. call trong block giống như sử dụng yield. Một vài người thích sử dụng call vì nó dễ hiểu code hơn yield.

Trả về giá trị

yield trả về giá trị cuối cùng (bên trong block ). Nói cách khác, giá trị mà yield trả về là giá trị của block

  def my_method
     value = yield
     puts "value is: #{value}"
  end

  my_method do
    2
  end

Kết quả:

value is 2
=> nil

Sử dụng vòng lặp trong block

Bạn có thể gọi đến yield nhiều lần, đó là lúc bạn nên sử dụng đến vòng lặp.

  def my_map(array)
    new_array = []

    for element in array
      new_array.push yield element
    end

    new_array
  end

  my_map([1, 2, 3]) do |number|
    number * 2
  end

Kết quả:

2
4
6

Khởi tạo đối tượng với các giá trị mặc định

Cách mà nó làm việc là viết trong hàm khởi tạo của ruby (initialize) có sử dụng yield(self), trong đó self là đối tượng được khởi tạo

class Car
  attr_accessor :color, :doors

  def initialize
    yield(self)
  end
end

car = Car.new do |c|
  c.color = "Red"
  c.doors = 4
end

puts "My car's color is #{car.color} and it's got #{car.doors} doors."

Kết quả:

My car's color is Red and it's got 4 doors.

Tổng kết

Block là một trong những tính năng mạnh mẽ của ruby nhưng thường xuyên bị bỏ quên. Bạn có thể thấy block không chỉ đơn giản là một đoạn code giữa doend, mà trong bài này ta còn được biết đến yield, nó cho phép bạn chèn các đoạn code vào bất cứ đâu trong phương thức. Điều đó có nghĩa là bạn có một phương thức mà có nhiều cách hoạt động khác nhau giống như có nhiều phương thức.

Hi vọng bài viết trên giúp bạn trong việc hiểu và sử dụng block và trợ thủ yield

Tài liệu tham khảo: https://mixandgo.com/blog/mastering-ruby-blocks-in-less-than-5-minutes Mastering ruby blocks in less than 5 minutes của tác giả Cezar Halmagean