Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Ruby Type Conversion: ใช้ to_s, to_a, to_str สำหรับการจัดการข้อมือราบรื่น

คุณกำลังทำงานกับ integer แต่อยากใช้ string methods (เช่น gsub) แทน

ทำได้อะไร?

แปลงเป็น string (ด้วย to_s) แล้วแปลงกลับเป็น integer (ด้วย to_i)

ตัวอย่าง:

คุณแปลง Integer 1 เป็น String "1"

จากนั้นใช้เมธอดจากคลาสใหม่ ช่วยทำสิ่งที่ทำไม่ได้ก่อนหน้า

จำไว้ว่าใน Ruby…

ทุกออบเจกต์เชื่อมโยงกับคลาส และทุกคลาสมีชุดเมธอดเฉพาะ

ในบทความนี้ คุณจะเรียนรู้:

  • Conversion methods ที่มีใน Ruby
  • ความแตกต่างระหว่างพวกมัน!
  • วิธีเลือกตัวที่เหมาะสมในสถานการณ์ต่างๆ

มาเริ่มกัน!

Short Conversion Methods (to_s, to_i)

คุณคุ้นเคยกับกลุ่มแรกของ conversion methods นี้

เมธอดอย่าง:

  • to_i
  • to_s
  • to_a

เมธอดเหล่านี้คืนออบเจกต์ใหม่ของคลาสเฉพาะที่ represent ออบเจกต์ปัจจุบัน

ตัวอย่าง:

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

นี่หมายถึง:

"ผมอยากแปลง Range 1..10 เป็น Array ที่ represent range นั้น"

มีวิธีที่ Ruby เรียก conversion methods เหล่านี้ให้คุณ implicitly

เช่นใน string interpolation:

"#{1}"

สิ่งนี้เรียก 1.to_s ให้คุณ แม้คุณไม่เห็น

คุณตรวจสอบเองได้ด้วยโค้ดนี้:

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

Note: คุณต้องใช้ Fixnum แทน Integer หากอยู่ Ruby 2.3 หรือเก่า หรืออัปเดต Ruby ดีกว่า 🙂

เมธอดเหล่านี้ permissive ค่อนข้าง และไม่ควร raise exception

ตัวอย่าง:

"aaaaaa".to_i # 0

0 นี้อาจทำให้ประหลาด

แต่นั่นคือสิ่งที่คุณได้เมื่อเรียก to_i บน string โดยไม่มี integers

เช่นที่คุณจะเห็นภายหลัง มี version ที่ strict กว่าของเมธอดนี้

Long Conversion Methods (to_str, to_int)

ตอนนี้:

หากเรามี short conversion methods ทำไมต้องการเมธอดอย่าง to_str หรือ to_int?

ความแตกต่างคืออะไร?

ความแตกต่างอยู่ที่ intent (เจตนา)

ทุก Ruby class (ยกเว้น BasicObject) implement เมธอด to_s เพื่อคืนตัวเองเป็น string representation ประเภทหนึ่ง

แตเพราะคลาสคืน string ไม่ได้หมายถึงมัน behave เหมือน string!

มา看看ตัวอย่าง:

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

คิดดู:

Empty string บวก integer ควรคืนอะไร?

ผมไม่รู้

คุณอาจพูดว่า "1" (string ที่มีเลขหนึ่ง)

แตทำไม?

นั่นไม่ใช่สิ่งที่คนส่วนใหญ่คาดหวังในกรณีนี้

มันไม่มีเหตุผลที่จะบวกกัน… นั่นคือเหตุผลที่เราได้ TypeError

และแม้จะ allow

อะไรกับนี้:

"" + {}

Empty string บวก empty hash

ไม่มีเหตุผลเช่นกัน!

ดังนั้น Ruby แทนที่จะตรวจสอบว่าออบเจกต์อีกตัวเป็น string (ซึ่งไม่ดีสำหรับ Polymorphism) มันตรวจสอบว่ามัน ACT เหมือน string

นั่นคือที่มาของเมธอด to_str

คลาสที่ implement to_str ใน Ruby 2.5 มีแค่:

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

วิธี Implement Conversion Methods เอง

คุณ implement to_str บนคลาสไหนก็ได้

จากนั้นคุณใช้มันเหมือน string ได้

ตัวอย่าง:

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

แต เว้นแต่คลาสของคุณ equivalent กับ string ไม่ควรทำนี้

ใช้ to_s แทน

Btw นี่ไม่ได้แค่เมธอด +

ยังใช้ในที่อื่นที่แค่ string-like object ถึงจะมีเหตุผล

เช่น:

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

Long conversion methods อื่นๆ เช่น to_int และ to_hash ปฏิบัติตาม logic เดียวกัน

นั่นคือเหตุผลที่เรามีเมธอดต่างๆ นี้

วิธีใช้ Conversion Wrappers

หากยังไม่พอ conversion methods… ไม่ต้องกังวล เพราะผมมีอีกนิด!

ผมชอบเรียกว่า "Conversion Wrappers"

พวกมันคือ:

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

นี่คือเมธอดที่ดูแปลก!

สังเกต parentheses และ square brackets…

…มันคือสิ่งเดียวแยกเมธอดเหล่านี้จากชื่อคลาส

วัตถุประสงค์คืออะไร?

Array() จะแปลง อะไรก็ได้ เป็น array

ตัวอย่าง:

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

Logic แบบนี้???

เมธอดนี้ปฏิบัติตาม กฎเฉพาะเจาะจง:

  • หากออบเจกต์ respond_to to_ary หรือ to_a จะเรียกนั้นและคืนค่า
  • มิฉะนั้น จะใส่ออบเจกต์ลงใน empty array และคืนนั้น

นี่อธิบายพฤติกรรมด้านบน

มีประโยชน์หากคุณเขียนเมธอดที่คาดหวัง array แต่อาจได้อย่างอื่นและ crash app คุณทำให้มันเป็น array ด้วย Array() ก่อนเพื่อกันไว้

ตอนนี้ Integer()

มีกฎพิเศษ:

  • หากออบเจกต์เป็น string และเนื้อหา conform อย่างเคร่งครัดกับ valid numeric representation ใน Ruby เมธอดนี้คืน Integer Raise ArgumentError หาก format invalid
  • หากออบเจกต์ไม่ใช่ string จะพยายามเรียก to_int แล้ว to_i
  • Raise TypeError หากแปลงเป็น valid Integer ไม่ได้ด้วย conversion method

ตัวอย่าง:

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

เมธอด Integer() นี้มีประโยชน์หากอยากแน่ใจ 100% ว่าทำงานกับ Integer ที่ valid

ตอนนี้ Hash[]

คุณส่งอาร์เรย์ even elements ได้เพื่อ hash ใหม่:

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

มีประโยชน์หากสร้าง hash โดย merge elements ของสองอาร์เรย์ หรือใช้เมธอดอย่าง map

สรุป

คุณเรียนรู้ conversion methods ต่างๆ ใน Ruby ทำไมมีอยู่ และวิธีใช้งาน!

หวังว่าจะช่วยได้ 🙂

หากชอบบทความนี้ คุณจะชอบหนังสือของผม Ruby Deep Dive ดูสิ