So sánh giữa nil? và == nil
Có điểm gì khác biệt giữa nil? và == nil Sẽ không có gì khác biệt khi mà bạn nhìn vào kết quả trả về. Và tôi thích dùng nil? vì nó dễ đọc hơn. Nhưng đó chỉ là vấn đề về cảm nhận của mỗi người Tuy nhiên có một sự khác biệt nhỏ trong cách tính kết quả này. 1. nil? nil? là một phương thức được ...
Có điểm gì khác biệt giữa nil? và == nil
Sẽ không có gì khác biệt khi mà bạn nhìn vào kết quả trả về. Và tôi thích dùng nil? vì nó dễ đọc hơn. Nhưng đó chỉ là vấn đề về cảm nhận của mỗi người
Tuy nhiên có một sự khác biệt nhỏ trong cách tính kết quả này.
1. nil?
nil? là một phương thức được định nghĩa trên Object và NilClass.
# NilClass rb_true(VALUE obj) { return Qtrue; } # Object static VALUE rb_false(VALUE obj) { return Qfalse; }
Kiểm tra nil? chỉ là việc gọi một phương thức đơn giản. Đối tượng của bạn kế thừa từ class Object đã được cài đặt phương thức nil? và luôn trả về false
Object.new.nil? # return false
Lưu ý: Trong lớp cha của lớp Object là lớp BasicObject, phương thức nil? không được cài đặt
BasicObject.new.nil? # undefined method `nil?' for #<BasicObject:0x000000065e7940>
2. == nil
a == b chỉ là cú pháp để gửi thông điệp == từ phải sang trái cùng với một đối số duy nhất. Điều đó có nghĩa là a.==(b) đối với trường hợp tổng quát. Còn trong trường hợp cụ thể của chúng ta a.==(nil)
== là một phương thức được định nghĩa trên BasicObject:
rb_obj_equal(VALUE obj1, VALUE obj2) { if (obj1 == obj2) return Qtrue; return Qfalse; }
Từ tài liệu
Ở mức đối tượng, == trả về true chỉ khi giá trị so sánh và giá trị được so sánh có cùng một đối tượng
Vì vậy kết quả trả về true nếu hai biến đang trỏ đến cùng một đối tượng hoặc nếu lớp nhận đã ghi đè phương thức == theo cách khác. Và các lớp con được dùng để ghi đè == để thực hiện hành vi cụ thể của lớp. Điều đó có nghĩa là hiệu suất phụ thuộc vào việc thực hiện ==. Không giống như nil? không được ghi đè bằng các lớp con.
Hơi khó hiểu nhỉ. Để tôi giải thích điều này
a = :framgia b = :framgia a == b # return true a.object_id # return 9107228 b.object_id # return 9107228 c = "framgia" d = "framgia" c == d # return true c.object_id # return 53695100 d.object_id # return 38048440
Cả 2 phép so sánh đều trả về true. Nhưng a, b cùng thuộc 1 đối tượng vì có cùng object_id. Còn c, d không thuộc cùng một đối tượng vì ko cùng object_id, tức là c == d đã ghi đè phương thức ==
3. Giải pháp khác
Trong ruby, để kiểm tra mọi thứ người ta hay đem ra so sánh với false hoặc nil.Nhưng bạn cũng có thể bỏ qua việc so sánh này bằng cách kiểm tra chính đối tượng mà bạn đang dùng
if some_object puts "some_object is neither nil nor false" # Một vài đối tượng không phải nil cũng chẳng phải false end
4. Hiệu năng
Tôi mong ước nil? có thể nhanh được như == nil. Bởi vì hiệu suất việc ghi đè == phụ thuộc vào receiver. Đây là một benchmark đơn giản để kiểm tra các giả định của tôi. Như thường lệ tôi sử dụng gem benchmark/ips của Evan Phoenix.
require 'benchmark/ips' class ExpensiveEquals def ==(other) 1000.times {} super(other) end end string = 'something' number = 123 expensive = ExpensiveEquals.new notnil = Object.new isnil = nil Benchmark.ips do |x| x.report('isnil.nil?') do if isnil.nil? end end x.report('notnil.nil?') do if notnil.nil? end end x.report('string.nil?') do if string.nil? end end x.report('number.nil?') do if number.nil? end end x.report('expensive.nil?') do if expensive.nil? end end x.report('isnil == nil') do if isnil == nil end end x.report('notnil == nil') do if notnil == nil end end x.report('string == nil') do if string == nil end end x.report('number == nil') do if number == nil end end x.report('expensive == nil') do if expensive == nil end end x.report('nil == isnil') do if nil == isnil end end x.report('nil == notnil') do if nil == notnil end end x.report('nil == string') do if nil == string end end x.report('nil == number') do if nil == number end end x.report('nil == expensive') do if nil == expensive end end x.report('isnil') do if isnil end end x.report('notnil') do if notnil end end x.report('string') do if string end end x.report('number') do if number end end x.report('expensive') do if expensive end end x.compare! end
Kết quả trả về:
notnil: 11840655.4 i/s expensive: 11801608.9 i/s - 1.00x slower number: 11679119.8 i/s - 1.01x slower string: 11598016.4 i/s - 1.02x slower isnil: 11529034.6 i/s - 1.03x slower notnil == nil: 10397262.7 i/s - 1.14x slower nil == expensive: 10319767.0 i/s - 1.15x slower nil == string: 10188393.9 i/s - 1.16x slower nil == number: 10167930.4 i/s - 1.16x slower isnil == nil: 10120560.0 i/s - 1.17x slower nil == notnil: 10069779.1 i/s - 1.18x slower nil == isnil: 10055165.2 i/s - 1.18x slower expensive.nil?: 9970905.5 i/s - 1.19x slower string.nil?: 9967045.3 i/s - 1.19x slower number.nil?: 9893974.5 i/s - 1.20x slower notnil.nil?: 9581974.5 i/s - 1.24x slower isnil.nil?: 8390963.6 i/s - 1.41x slower string == nil: 6915330.1 i/s - 1.71x slower number == nil: 6803969.3 i/s - 1.74x slower expensive == nil: 25382.6 i/s - 466.49x slower
chú thích: i/s là iterations/second
Theo như kết quả thì phép toán chạy chậm nhất expensive == nil chậm gấp 466.49 lần phép toán chạy nhanh nhất notnil (notnil được lấy ra làm đơn vị cơ bản để so sánh slower với các phép toán còn lại)
Tôi không mong muốn nil? lại chạy chậm đến vậy. Qua kết qua thu được thì việc kiểm tra nil == sẽ cho hiệu năng cao là bạn kiểm tra == nil. Và trong các phép kiểm tra thì kiểm tra chính đối tượng như được nêu ra ở phần 3. giải pháp khác đã đạt được hiệu năng cao nhất
5. Kết luận
Bài viết này mình dịch từ nguồn: http://pascalbetz.github.io/ruby/2016/05/17/nilvsequals/
Mong nhận được sự đóng góp ý kiến của các bạn