12/08/2018, 16:34

Ruby: Toán tử ||= và defined?

Trong phần lớn các ứng dụng Rails hoặc thậm chí là các gem Ruby, bạn có thể tìm thấy rất nhiều trường hợp bạn cần ghi nhớ kết quả của một hàm để tăng tốc ứng dụng của bạn khi mà hàm đó đã được tính toán. Giải pháp được sử dụng phổ biến nhất có lẽ là sử dụng toán tử ||=. Ví dụ: @result ||= ...

Trong phần lớn các ứng dụng Rails hoặc thậm chí là các gem Ruby, bạn có thể tìm thấy rất nhiều trường hợp bạn cần ghi nhớ kết quả của một hàm để tăng tốc ứng dụng của bạn khi mà hàm đó đã được tính toán. Giải pháp được sử dụng phổ biến nhất có lẽ là sử dụng toán tử ||=. Ví dụ: @result ||= do_some_heavy_computation Tuy nhiên, có một số trường hợp mà nó không phù hợp, khi đó bạn nên sử dụng toán tử defined?

Hãy quay lại ví dụ từ phần giới thiệu: @result ||= do_some_heavy_computation. Toán tử ||= nó hoạt động như thế nào? Nó gần giống với @result || @result = do_some_heavy_computation nhưng không hoàn toàn giống nhau mà hiểu là: "trả về giá trị của @result nếu giá trị là đúng hoặc gán kết quả của do_some_heavy_computation cho @result". Rõ ràng, phiên bản ngắn gọn này có vẻ hấp dẫn hơn. Nhưng hãy nhớ rằng, toán tử này không hẳn là gán giá trị cho biến mà là kiểm tra giá trị của biến đúng hay không. Vậy làm sao để kiểm tra 1 biến, trả ra nil khi nó chưa được định nghĩa và không gặp phải ngoại lệ nào?

Chúng ta có thể giải quyết vấn đề trên đây bằng việc sử dụng toán tử defined?, nó trả về nil nếu đối số chưa được định nghĩa, nếu đã được định nghĩa, nó trả về mô tả của đối số. Với defined? chúng ta có thể dễ dàng kiểm tra biến đã có hay chưa. Ví dụ:

defined?(@result) // => nil

@result = nil
defined?(@result) // => "instance-variable"

Vậy là chúng ta đã hiểu sự khác nhau giữa 2 toán tử ||= và defined?. Hãy tưởng tượng bạn có 1 hàm như sau:

def heavy_computation_result
  @result ||= do_some_heavy_computation
end

và bạn phải gọi heavy_computation_result nhiều lần để sử dụng kết quả của nó. Hãy xem hàm tính toán này rất nặng (như cái tên của nó             </div>
            
            <div class=

0