Phân loại so sánh bằng và cách nối chuỗi trong Ruby
Phân loại so sánh bằng trong ruby Như chúng ta đã biết so sánh bằng có các loại là : == , ===, eql?, equal? Giống nhau : Điểm giống nhau cơ bản giữa chúng là chúng đều dùng để so sánh và trả về giá trị là true hoặc false. Khác nhau : == ( generic equality ): So sánh có cùng giá trị hay ...
- Phân loại so sánh bằng trong ruby Như chúng ta đã biết so sánh bằng có các loại là : == , ===, eql?, equal?
Giống nhau : Điểm giống nhau cơ bản giữa chúng là chúng đều dùng để so sánh và trả về giá trị là true hoặc false.
Khác nhau :
- == ( generic equality ): So sánh có cùng giá trị hay không. Đây là cách so sánh phổ biến và cơ bản nhất trong hầu hết các ngôn ngữ lập trình.
- === ( Case equality ): Như tên gọi của nó, === là so sánh dạng case. Các điều kiện của case sẽ đc implement với mỗi class tương ứng. Ví dụ với:
- Range
- Regex
- Proc (in Ruby 1.9)
Ví dụ:
case some_object when /a regex/ # The regex matches when 2..4 # some_object is in the range 2..4 when lambda {|x| some_crazy_custom_predicate } # the lambda returned true end
(1..5) === 3 # => true (1..5) === 6 # => false Integer === 42 # => true Integer === 'fourtytwo' # => false /ell/ === 'Hello' # => true /ell/ === 'Foobar' # => false "a" === "b" # false # different values, different objects "a" === "a" # true # same values
Như vậy === cũng đơn thuần là so sánh giá trị chứ không phải là so sánh object có điều nó dùng case để so sánh và === còn được gọi là Case equality.
"test" == "test" #=> true "test" === "test" #=> true # #sự khác nhau giữa == và === là ở đây String === "test" #=> true String == "test" #=> false
- Eql? — Hash equality: Method này sẽ trả về true nếu 2 tham số có cùng hash key. Nó sử dụng Hash để kiểm tra các member có giống nhau hay không. Với Object thì Eql? giống như ==(chỉ so sánh value) và hầu hết các subclasses cũng như vậy.
Tuy nhiên với kiểu Numeric thì có ngoại lệ, nó chỉ kiểm tra 2 tham số có cùng giá trị và cùng Class hay không.
Ví dụ:
1 == 1.0 #=> true | vì == chỉ so sánh giá trị 1.eql? 1.0 #=> false | vì chúng khác Class 1.class #=> Fixnum 1.0.class #=> Float
- Equal? — So sánh giá trị và object_id của object.
object_id là method trả về định danh của đối tượng. Nếu hai đối tượng có chung một object_id thì chúng giống nhau tức là đều trỏ đến cùng một đối tượng trong vùng nhớ và ngược lại.
Equal? là cách hiệu quả để so sánh con trỏ, dùng để kiểm tra chính xác xem có cùng là 1 Object hay không. để hiểu rõ hơn ta xem ví dụ sau:
2.1.0 :001 > a = "viblo.asia" 2.1.0 :002 > b = "viblo.asia" 2.1.0 :003 > c = d = "viblo.asia" 2.1.0 :004 > a.equal?b # false 2.1.0 :005 > c.equal?d # true
Bây giờ ta cùng xem object_id của chúng
2.1.0 :005 > a.object_id # 19088820 2.1.0 :007 > b.object_id # 19008500 2.1.0 :008 > c.object_id # 18854700 2.1.0 :009 > d.object_id # 18854700
Ta thấy c và d có cùng object_id là 18854700 và kết quả trả về là false.
Như vậy Equal? sẽ so sánh cả object_id nên mặc dù value của a, b, c, d cùng là viblo.asia nhưng chúng có object_id khác nhau dẫn đến kết quả trả về là false.
2.SỰ KHÁC NHAU CỦA << & += TRONG VIỆC NỐI CHUỖI
- Nối chuỗi với +=
2.1.0 :010 > first_name = "Viblo" 2.1.0 :011 > name = first_name 2.1.0 :012 > last_name = "Asia" 2.1.0 :013 > name += last_name 2.1.0 :014 > name # VibloAsia 2.1.0 :015 > first_name # Viblo
- Nối chuỗi với <<
2.1.0 :010 > first_name = "Viblo" 2.1.0 :011 > name = first_name 2.1.0 :012 > last_name = "Asia" 2.1.0 :013 > name << last_name 2.1.0 :014 > name # VibloAsia 2.1.0 :015 > first_name # VibloAsia
kiểm tra object_id của name, first_name
2.1.0 :016 > name.object_id --> 15533700 2.1.0 :017 > first_name.object_id --> 15533700
Phép gán name = first_name lúc này name & first_name có cùng 1 object_id và khi thực hiện:
-
- << sẽ xử lý trực tiếp trên object của nó, vì vậy khi name thay đổi thì first_name cũng thay đổi theo.
- += sẽ tạo ra một object mới sau khi thực hiện cộng chuỗi xong mới gán lại giá trị cho object cũ, vì vậy khi thay đổi name thì first_name không bị ảnh hưởng.
Chúng ta cùng sử dụng benchmark để xem thời gian thực hiện của 2 cách này:
require 'benchmabash' n = 10000 Benchmark.bm do |benchmark| benchmark.report("+=") do n.times do first_name = "Viblo" name = first_name last_name = "Asia" name += last_name end end benchmark.report("<<") do n.times do first_name = "Viblo" name = first_name last_name = "Asia" name << last_name end end end
kết quả
user system total real += 0.010000 0.000000 0.010000 ( 0.007283) << 0.000000 0.000000 0.000000 ( 0.004042)
Qua đó mình thấy được tốc độ xử lý của << sẽ nhanh hơn +=. Đây cũng chính là lý do << được sử dụng phổ biến hơn