Ruby có từ khóa defined? giúp kiểm tra biến có được định nghĩa hay không.
Nếu biến tồn tại bạn sẽ nhận được kiểu của nó:
apple = 1 defined?(apple) # "local-variable"
Nếu không thì nhận nil:
defined?(bacon) # nil
Điều này giống toán tử typeof của Javascript. Nếu muốn biết class của object, dùng phương thức class thay vì này.
Một số điểm thú vị:
defined?là từ khóa, không phải phương thứcdefined?là một trong những thứ ít trong Ruby kết thúc bằng dấu hỏi nhưng không tuân theo quy ước trả vềtruehoặcfalsedefined?phân biệt được giữa giá trị nil và biến chưa bao giờ được set
Những đặc điểm đặc biệt này làm cho từ khóa này đáng để học.
Cách tốt hơn kiểm tra biến đã định nghĩa
Từ khóa này hữu ích nhưng có vấn đề.
Tại sao?
Vì độ ưu tiên toán tử thấp.
Nếu bạn làm như này:
defined? orange && orange.size
Kết quả là "expression".
Vì orange && orange.size được hiểu là đối số của defined?.
Cách đúng:
defined?(orange) && orange.size
Ruby có cách khác kiểm tra biến đã định nghĩa.
Cho biến cục bộ:
local_variables.include?(:orange)
Cho instance variable:
instance_variable_defined?("@food")
Nhưng bạn không muốn dùng những cái đó.
Trong 99% trường hợp, nếu biến cục bộ thiếu thì bạn bị typo hoặc ai đó quên khai báo biến.
Còn instance variable?
Instance variable chưa định nghĩa luôn là nil, nên bạn muốn check nil.
Thử "safe navigator operator" (Ruby 2.3+) chỉ gọi phương thức nếu biến không nil.
Ví dụ:
if @user&.country == "Spain" # ... end
Điều này tương đương với:
if @user && @user.country == "Spain" # ... end
Các cách này không universal như defined? nhưng dễ dự đoán và ít lỗi hơn.
Kiểm tra phương thức có định nghĩa không
Bạn có thể dùng defined? kiểm tra phương thức nhưng không thực tế.
Ví dụ:
defined?(puts) # "method"
Vì nó là từ khóa không phải phương thức, bạn không dùng với object.
Đây là điều tôi nói:
[].defined?(:size) # undefined method `defined?' for []:Array
Bạn tìm phương thức respond_to?.
Cách dùng:
[].respond_to?(:size) # true [].respond_to?(:orange) # false
Kiểm tra Class có tồn tại không
Ví dụ:
defined?(Object) # "constant" defined?(A) # nil
Tùy chọn tốt hơn là dùng phương thức const_defined?.
Như sau:
Object.const_defined?(:String) # true Object.const_defined?(:A) # false
Tóm tắt
Đây, bạn đã học cách dễ dàng kiểm tra biến, class hoặc phương thức có tồn tại!
Khi làm việc với biến, điều bạn thường muốn là check nil, thay vì xem biến có định nghĩa hay không. Hoặc tốt hơn, chuyển biến thành class đã biết dùng conversion method.
Hy vọng bài viết hữu ích! Nếu có, hãy chia sẻ để nhiều người hơn tận hưởng.