11/08/2018, 21:42

Toán tử &. trong Ruby

Trong bài viết trước mình đã giới thiệu về những lỗi thường gặp trong ứng dụng Rails, trong đó có lỗi khi gọi phuơng thức không tồn tại của object nil. Ở bài viết này mình sẽ nói kĩ hơn về toán tử &. để phòng tránh lỗi trên. Bối cảnh Giả sử bạn có một account, trong account có chứa thông ...

Trong bài viết trước mình đã giới thiệu về những lỗi thường gặp trong ứng dụng Rails, trong đó có lỗi khi gọi phuơng thức không tồn tại của object nil. Ở bài viết này mình sẽ nói kĩ hơn về toán tử &. để phòng tránh lỗi trên.

Bối cảnh

Giả sử bạn có một account, trong account có chứa thông tin của owner và bạn muốn lấy address của owner. Nếu bạn muốn chương trình chạy một cách an toàn và không bị lỗi Ruby undefined method ... for nil:NilClass (NoMethodError) thì phải viết tương tự như sau:

if account && account.owner && account.owner.address
...
end

Nhìn rất dài dòng và rườm rà! ActiveSupport có hỗ trợ phuơng thức try có tác dụng tương tự trong trường hợp này

if account.try(:owner).try(:address)
...
end

Với Ruby 2.3 trở lên, chúng ta có thể sử dụng toán tử &. để viết lại ví dụ bên trên cho gọn hơn như sau

account&.owner&.address

So sánh

Xét một vài ví dụ dưới đây

  • Trong trường hợp account có owner là nil, không có gì quá ngạc nhiên, 3 cách xử lý trên có kết quả giống nhau
account = Account.new(owner: nil) # account without an owner

account.owner.address
# => NoMethodError: undefined method `address' for nil:NilClass

account && account.owner && account.owner.address
# => nil

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => nil
  • Trong trường hợp owner là false
account = Account.new(owner: false)

account.owner.address
# => NoMethodError: undefined method `address' for false:FalseClass `

account && account.owner && account.owner.address
# => false

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => undefined method `address' for false:FalseClass`

Ta thấy rằng toán tử &. chỉ có tác dụng với nil object và hoàn toàn không có tác dụng với false object.

  • Trong trường hợp owner không tồn tại method hoặc property address
account = Account.new(owner: Object.new)

account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>

account && account.owner && account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

Với ví dụ trên ta thấy rằng method try không hề check nếu được truyền vào có tồn tại hay không. Nếu muốn check điều này, ta có thể sử dụng try!

account.try!(:owner).try!(:address)
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
  • Chú ý khi sử dụng toán tử &. với method nil?.
nil.nil?
# => true

nil&.nil?
# => nil

Ví dụ này mình cũng không biết giải thích thế nào =))

Kết

Hi vọng qua bài viết nhỏ này, các bạn có thể hiểu hơn về toán tử &. và có thể sử dụng nó một cách thích hợp (nhớ là từ Ruby 2.3 trở lên mới có nhá, dự án cũ quá thì chưa support đâu!).

0