Optional
ในภาษา Swift กำหนดว่าตัวแปรทุกตัวที่ไม่ใช่ตัวแปรประเภท Optional จะไม่สามารถมีค่าเป็น nil
ได้
เพื่อให้เวลาที่เราอ่านโค้ด สามารถรู้ได้ว่า เราต้อง ตรวจสอบหรือไม่ต้องตรวจสอบ nil
ซึ่งจะช่วยลดการเกิด runtime error รวมทั้งลดการเขียนแบบ defensive programming ที่มากเกินไป
Optional เป็น Type ใหม่ที่มี associated type เป็น type ต่าง ๆ เช่น String
Int
หรืออื่น ๆ
ค่า default ของ Optional จะมีค่าเป็น nil
เสมอ
ตัวแปรประเภทที่ไม่ใช่ optional จะไม่มีค่า default หรือ zero value ให้ทำให้ทุกครั้งที่ประกาศตัวแปรที่ไม่ใช่ optional จะต้องมีการ assign ค่าให้เสมอ
ในการประกาศให้ตัวแปรเป็น Optional ให้เราประกาศเหมือนตัวแปรปกติ แต่ที่ Type เราจะใส่ ?
หรือ !
ลงท้าย เช่น
ในการถอดค่าเพื่อเอา value ใน optional มาใช้ในรูปแบบปกติ เช่น การถอดจาก String?
เป็น String
หรือ String!
เป็น String
เรียกว่า unwraping ซึ่งวิธีการจะมีสิ่งที่เรียกว่า Optional Binding
ซึ่งก็คือ การทดสอบว่า nil
ไหมนั่นเอง จะมีหน้าตาประมาณนี้
ถ้าจากตัวอย่างจะเห็นว่า ในการแปลงค่าจาก String
เป็น Int
สามารถที่จะแปลงกลายเป็น nil
ได้เพราะว่า แปลงไม่สำเร็จ เช่น amount เป็น "abc"
แทนที่จะเป็นตัวเลข
ทำให้ Int(amount)
คืนผลลัพธ์ที่เป็น Int?
นั่นคืออาจเป็น nil ได้
การที่เราจะทำให้เป็น Int ได้ เราจึงต้องใช้ if let
มาช่วย จากตัวอย่างนั่นคือ ถ้า Int(amount)
ให้ผลลัพธ์ที่ไม่ใช่ nil
เราจะได้ตัวแปรใหม่ชื่อว่า total
มี Type เป็น Int
และใช้ค่าได้ภายใต้ scope ของ if นี้
ในกรณีที่ Int(amount)
ให้ผลลัพธ์ nil
โค้ดจะรันส่วน else
แทน
ในบางครั้งเราสามารถถอด optional โดยกำหนดค่า default แทนได้ เช่น เราต้องการให้ค่าเป็น 0
กรณีที่เราไม่สามารถถอดค่าได้
?
กับ !
ต่างกันอย่างไร
?
กับ !
ต่างกันอย่างไรทั้งคู่ล้วนเป็น optional เหมือนกัน ต่างกันตรงที่การใช้ !
หมายความว่า ณ เวลาที่ใช้ผู้เขียนแน่ใจว่าค่าจะไม่เป็น nil
นั่นคือ เมื่อเราประกาศแบบ !
เราจะสามารถเขียนโค้ดเหมือนตัวแปรแบบปกติ คือ เราสามารถ assign ให้โดยไม่ต้องทำ unwrap ได้ แบบนี้
นั่นคือ เราสามารถเขียน total + amount
ได้เลยโดยที่ไม่ต้องทำแบบนี้
การใช้ !
ต้องแน่ใจว่าเวลาที่ใช้ค่าตัวแปรนั้น จะต้องไม่มีค่าเป็น nil
เพราะถ้ามีค่าเป็น nil
การใช้ค่าโดยไม่ unwrap ก่อนจะทำให้เกิด runtime error และ application ของเราก็จะ crash
โดยปกติเราจะไม่ใช้ !
ยกเว้น เช่นตัวแปรที่ใช้เชื่อมกับ view ซึ่งเรามั่นใจว่า view นั้นจะไม่ใช้ nil
แน่นอนในเวลาที่รัน
ในบางครั้งจุดที่เราต้องการให้มีค่าจริง ๆ ถ้าไม่มีให้ crash ก็ช่วยในการ detect bug ได้ แต่นั่นเราต้องมั่นใจว่าเราเทสได้ครอบคลุม
นอกจาก Optional Binding แล้ว เรายังมี optional chaining นั่นคือในบางครั้งเราก็ไม่จำเป็นต้องถอดจนครบทีละตัว แต่สนใจที่ผลลัพธ์สุดท้าย ให้เราใส่ ?
หรือ !
ไปตามจุดต่าง ๆ ใน statement เรา เช่น
ตัวอย่างนี้ จะเห็นว่าเราไม่ได้ unwrap Double?
ก่อนแล้วค่อย rounded()
ใน if
ในกรณีนี้เราใส่ ?
หลัง Double("123.45")
แล้ว rounded()
การทำแบบนี้ optional chaining ซึ่งการใส่ ?
จะยังทำให้ผลลัพธ์ทั้งหมดของ statement นี้ยังเป็น Double?
เราจึงยัง unwrap ด้วย optional binding ต่อด้วย if let
ถ้า Double("123.45")
ให้ผลลัพธ์เป็น nil
ฟังก์ชันrounded()
จะไม่ถูกเรียก และให้ผลลัพธ์เป็น nil
เลย
optional chaining ก็สามารถใช้ !
ได้ เรียกว่า force unwrap แต่ให้ผลลัพธ์เป็นตัวแปรชนิดที่ไม่ใช่ optional นั่นคือ เมื่อเรียกบนตัวแปรที่เป็น nil
จะทำให้ application crash ได้
สามารถอ่านเพิ่มเติมได้ที่
Last updated