คุณกำลังทำงานกับ 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]
นี่หมายถึง:
"ผมอยากแปลง
Range1..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 มีแค่:
StringNameError::messageWarning::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หากแปลงเป็น validIntegerไม่ได้ด้วย 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 ดูสิ