Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thành thạo Type Conversion Ruby: Dùng to_s, to_a, to_str thao tác dữ liệu mượt mà

Bạn làm việc với integer nhưng muốn dùng phương thức string (như gsub).

Làm sao?

Convert thành string (với to_s) rồi convert ngược integer (với to_i).

Ví dụ:

Bạn convert Integer 1 thành String "1".

Sau đó dùng phương thức class mới, giúp làm việc không thể trước.

Nhớ trong Ruby…

Mọi object liên kết với class, và mỗi class có tập phương thức riêng.

Trong bài này, bạn học về:

  • Conversion method nào có sẵn trong Ruby
  • Khác biệt giữa chúng!
  • Cách chọn đúng cái trong tình huống khác nhau

Bắt đầu!

Short Conversion Methods (to_s, to_i)

Bạn có thể quen nhóm conversion method đầu tiên.

Phương thức như:

  • to_i
  • to_s
  • to_a

Các phương thức này trả về object mới của class cụ thể đại diện cho object hiện tại.

Ví dụ:

 (1..10).to_a # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Điều này nói:

"Tôi muốn convert Range 1..10 thành Array đại diện range đó."

Có cách Ruby gọi conversion method này ngầm cho bạn.

Như string interpolation:

 "#{1}" 

Này gọi 1.to_s cho bạn, dù bạn không thấy.

Bạn tự check với code này:

 module Log
  def to_s
    puts "to_s called"
    super
  end
end
class Integer
  prepend Log
end
puts "#{1}" # "to_s called" 

Lưu ý: Dùng Fixnum thay Integer nếu Ruby 2.3 hoặc cũ. Hoặc tốt hơn, update Ruby 🙂

Các phương thức này khá permissive và không raise exception.

Ví dụ:

 "aaaaaa".to_i # 0 

Con số 0 này có thể bất ngờ.

Nhưng đó là kết quả khi gọi to_i trên string không có integer.

Sau bạn thấy phiên bản strict hơn của phương thức này.

Long Conversion Methods (to_str, to_int)

Bây giờ:

Nếu đã có short conversion method, tại sao cần to_str, to_int?

Khác biệt là gì?

Khác biệt nằm ở intent (ý định).

Mọi Ruby class (trừ BasicObject) implement to_s trả về string representation.

Nhưng chỉ vì class trả string không nghĩa nó behave như string!

Xem ví dụ:

 "" + 1 # TypeError: no implicit conversion of Fixnum into String 

Suy nghĩ:

String rỗng cộng integer nên trả gì?

Tôi không biết.

Bạn nói "1" (string có số 1).

Tại sao?

Đó không phải kỳ vọng đa số trong case này.

Không hợp lý cộng chúng… nên TypeError.

Và ngay cả nếu cho phép.

Cái này thì sao:

 "" + {} 

String rỗng cộng hash rỗng.

Cũng không hợp lý!

Vậy Ruby thay vì check object khác có phải string (không tốt cho Polymorphism), nó check xem nó CÓ HIỂU NHƯ string không.

Đó là lúc to_str xuất hiện.

Chỉ các class implement to_str trong Ruby 2.5:

  • String
  • NameError::message
  • Warning::buffer

Cách implement Conversion Method riêng

Bạn implement to_str trên bất kỳ class.

Sau đó dùng nó như string.

Ví dụ:

 class Cat
  def to_str
    "meow"
  end
end
"" + Cat.new # "meow" 

Nhưng trừ khi class bạn equivalent với string thì không nên làm này.

Dùng to_s thay thế.

Btw, này không chỉ cho phương thức +.

Cũng dùng ở chỗ khác chỉ string-like object mới hợp lý.

Như:

 [1,2,3].join(",") 

Các long conversion method khác như to_int và to_hash theo logic tương tự.

Đó là lý do chúng ta có các phương thức khác nhau.

Cách dùng Conversion Wrappers

Nếu chưa đủ conversion method… đừng lo vì còn vài cái nữa!

Tôi gọi chúng "Conversion Wrappers".

Chúng là:

  • Array()
  • Integer()
  • Hash[]

Đó là phương thức trông lạ!

Chú ý ngoặc đơn và ngoặc vuông…

…là điều duy nhất tách biệt phương thức này với tên class.

Mục đích?

Array() convert BẤT KỲ THỨ GÌ thành array.

Ví dụ:

 Array(nil) # []
Array([]) # []
Array(1) # [1]
Array("") # [""] 

Logic gì đây???

À, phương thức này tuân theo quy tắc cụ thể:

  • Nếu object respond_to to_ary hoặc to_a, nó gọi đó và trả value
  • Ngược lại, nó đưa object vào array rỗng và trả đó

Điều đó giải thích behavior trên.

Hữu ích nếu viết method expect array nhưng nhận bất cứ thứ gì và crash app. Bạn đảm bảo nó array bằng cách pass vào Array() trước.

Bây giờ Integer().

Có quy tắc đặc biệt:

  • Nếu object là string và nội dung strict conform valid numeric representation Ruby, method trả Integer. Raise ArgumentError nếu format invalid.
  • Nếu object không phải string, thử gọi to_int, rồi to_i.
  • Raise TypeError nếu object không convert được thành Integer hợp lệ dùng conversion method.

Ví dụ:

 Integer(1) # 1
Integer("25") # 25
Integer("abc123") # ArgumentError (invalid value for Integer(): "abc123")
Integer([]) # TypeError (can't convert Array into Integer) 

Phương thức Integer() hữu ích nếu muốn 100% chắc chắn làm việc với Integer hợp lệ.

Bây giờ Hash[].

Bạn truyền mảng số phần tử chẵn để có hash mới:

 Hash[[["a", 1], ["b", 2], ["c", 3]]] # {"a"=>1, "b"=>2, "c"=>3} 

Hữu ích nếu build hash bằng merge element hai mảng, hoặc dùng method như map.

Tóm tắt

Bạn đã học các conversion method khác nhau trong Ruby, tại sao chúng tồn tại và cách dùng!

Hy vọng hữu ích 🙂

Nếu thích bài này bạn cũng sẽ yêu thích sách Ruby Deep Dive, check it out.