Xử lý hash fallbacks

Có thể các bạn không biết, có nhiều cách để lấy một giá trị trong hash. Trong bài viết này, tôi sẽ nói về ba trong số chúng và những tác dụng của mỗi phương pháp.

Phương thức #[]

Cách đầu tiên cũng là cách được hầu hết developer biết đến và ưa thích, đó là phương thức #[]. Đây là phương thức chúng ta được học đầu tiên khi sử dụng hash, đây là cách mà các lập trình viên của các ngôn ngữ khác dùng để truy cập vào phần tử của mảng hoặc hash. Để truy cập vào hash trong ruby nó được sử dụng như sau:

pets = { cat: "Jess" }
pets[:cat]
# => "Jess"

Nó chính xác là những gì chúng ta muốn. Nhưng nếu trong trường hợp phần tử chúng ta truy cập đến không tồn tại thì sẽ như thế nào? Điều gì sẽ xảy ra?

pets = { cat: "Jess" }
pets[:dinosaur]
# => nil

Nó sẽ trả về giá trị nil. Không vấn đề gì, chúng ta có suy nghĩ cách để xử lý tiếp với kết quả trả về này. Có thể làm như sau:

pets = { cat: "Jess" }
pets[:dinosaur] || "They all died :("
# => "They all died :("

Có vẻ ổn. Nhưng điều gì sẽ xảy ra nếu giá trị chúng ta truy cập trong hash tồn tại nhưng nó lại là false

dinosaurs = { alive?: false }
dinosaurs[:alive?] || true
# => true

Nó sẽ trả về giá trị fallback khi chúng ta truy cập vào hash, nhưng rõ ràng là phần tử mà chúng ta muốn lấy ra từ hash có tồn tại, và kết quả chúng ta muốn là giá trị của nó chứ không phải giá trị fallback. Để làm được điều này một cách dễ dàng nhất, chúng ta có thể dùng cách sau.

Phương thức fetch

Phương thức fetch hoạt động gần như là giống với #[], nhưng nó cho phép bạn set một giá trị fallback khi gặp trường hợp key không tồn tại hoặc giá trị trong hash là nil

pets = { cat: "Jess" }
pets.fetch(:dinosaur, "They all died :(")
# => "They all died :("

Ở ví dụ trên nó chẳng khác gì #[], tuy nhiên nó đã giải quyết được vấn đề của trường hợp sau đó:

dinosaurs = { alive?: false }
dinosaurs.fetch(:alive?, true)
# => false

Đây có vẻ như là một giải pháp tốt hơn nhiều so với phương pháp ban đầu. fetch chỉ trả về giá trị fallback khi key chúng ta dùng không tồn tại trong hash, hoặc khi giá trị nhận được là nil, ở đây trường hợp key là alive? thì nó sẽ trả về giá trị trong hash là false. Bây giờ chúng ta lại xét một trường hợp khác như sau:

pets.fetch(:dinosaur, Dinosaur.raise_from_the_dead!)

Khi chúng ta sử dụng hai đối số cho phương thức fetch, đối số thứ hai sẽ luôn được xem xét mặc dù có thể nó không bao giờ được sử dụng. Và nó có thể là một biểu thức, chúng ta sẽ tốn thêm thời gian và công sức chạy nó để lấy được giá trị là đối số truyền vào phương thức fetch. Ở một số trường hợp việc chạy nhưng biểu thức đó sẽ dẫn đến những điều không mong muốn. Vậy có cách nào để chỉ gọi đến fallback khi thực sự cần nó? May mắn là có cách để làm điều này:

pets.fetch(:dinosaur) { Dinosaur.raise_from_the_dead! }

Chúng ta sẽ chỉ gọi đến phương thức raise_from_the_dead! của Dinosaur khi thực sự không có một con dinosaur nào. Mọi thứ đã trở nên hợp lý.

Kết luận

Bài viết này khá đơn giản đối với cả những người mới làm quen với hash trong ruby. Nhưng nó lại khá hữu dụng trong một số trường hợp cụ thể, giúp developer tránh việc phải dùng những đoạn code phân nhánh dài dòng và không đẹp. * References


All Rights Reserved