Toán tử === trong Ruby
Bài đăng này đã không được cập nhật trong 7 năm
Gần đây công việc của tôi hay dùng tới với module Enumerable
của Ruby. Và tôi cố gắng cân bằng giữa việc học các API phổ biến nhất (mà có thể bạn đã biết) với các API ít phổ biến hơn nhưng rất hữu ích. Qua đó tôi cũng học được rất nhiều điều thú vị. Sau đây tôi sẽ chia sẻ một trong số những điều mà tôi cảm thấy hứng thú và đáng chú ý. Chúng ta hãy xét ví dụ sau về method grep
của module Enumerable
# grep(pattern) → array
# Returns an array of every element in enum
# for which Pattern === element.
(1..100).grep(38..44)
#=> [38, 39, 40, 41, 42, 43, 44]
names = %w(
William
Kate
Adam
Alexa
James
Natasha
)
names.grep(/am/)
# => %w(William Adam James)
Như ví dụ trên ta nhận thấy là method grep
hoạt động với bất kỳ class nào có toán tử ===
, điều này làm tôi tò mò là những class nào thực hiện nó và nó thực hiện bằng cách nào. Hãy cùng tìm hiểu.
Class/Module
mod === obj #→ true or false
===
trả về true khi obj
là 1 thể hiện của mod
hoặc hậu duệ của mod
Nó về cở bản giống với method kind_of?
:
obj.kind_of?(mod)
Ví dụ
"text".class.ancestors
# => [String, Comparable, Object, Kernel, BasicObject]
String === "text"
# => true
Object === "text"
# => true
Comparable === "text"
# => true
Numeric === "text"
# => false
Regexp
rxp === str #→ true or false
Ở trường hợp của Regexp
, ===
giống với:
rxp =~ str >= 0
Ví dụ
/^[a-z]*$/ === "HELLO"
#=> false
/^[A-Z]*$/ === "HELLO"
#=> true
Range
rng === obj #→ true or false
trả về true
nếu obj là phần tử thuộc rng
, ngược lại trả về false
Ví dụ
(Date.new(2017, 8, 21)..Date.new(2017, 8, 27)) === Date.new(2017, 8, 27)
# => true
(Date.new(2017, 8, 21)..Date.new(2017, 8, 27)) === Date.new(2017, 8, 29)
# => false
("a".."z") === "a"
# => true
("a".."z") === "abc"
# => false
Proc
proc === obj # → result_of_proc
Gọi khối lệnh trong proc với params là obj Ví dụ
is_today = -> (date) { Date.current === date }
is_today === Date.current
# => true
is_today === Date.tomorrow
# => false
is_today === Date.yesterday
# => false
Object
Đối với hầu hết các object thì toán tử ===
giống với ==
Your class
Có một câu hỏi là nếu bây giờ chúng ta tự tạo ra class
riêng và khai báo method ===
thì khi dùng grep
sẽ như thế nào.
Chúng ta xét ví dụ sau:
class State
def initialize(expected_state)
@expected_state = expected_state
end
def ===(obj)
obj.state.to_s == @expected_state.to_s
end
end
class Order < Struct.new(:id, :state, :customer_name)
end
p = Order.new(1, "placed", "Robert")
v = Order.new(2, "verified", "Anne")
s = Order.new(3, "shipped", "Kate")
orders = [p,v,s]
verified = State.new(:verified)
placed = State.new(:placed)
verified === p
# => false
orders.grep(verified)
# => [#<struct Order id=2, state="verified", customer_name="Anne">]
message = case v
when verified
"Your order has been verified and is awaiting shippment"
when placed
"Please wait for verification"
else
"---"
end
# => "Your order has been verified and is awaiting shippment"
Qua ví dụ trên ta thấy có thể dùng thể hiện của class mình tạo ra match với cả trường hợp dùng case...when và trường hợp Array#grep
Your object
Ruby cho phép bạn định nghĩa một phương thức Singleton chỉ ảnh hưởng đến hành vi của một đối tượng duy nhất, thậm chí không cần class. Ví dụ
VERIFIED = Object.new
def VERIFIED.===(obj)
obj.state.to_s == "verified"
end
class Order < Struct.new(:id, :state, :customer_name)
end
VERIFIED === Order.new(1, "placed", "Robert")
# => false
VERIFIED === Order.new(2, "verified", "Rita")
# => true
Nhưng tốt hơn thì nên dùng Proc cho trường hợp này
VERIFIED = -> (obj){ obj.state.to_s == "verified" }
Reference
Nguồn: http://blog.arkency.com/the-equals-equals-equals-case-equality-operator-in-ruby/ Mong rằng bài viết này giúp bạn hiểu và thấy hứng thú hơn với Ruby. Thanks.
All rights reserved