Optional
ในภาษา Swift กำหนดว่าตัวแปรทุกตัวที่ไม่ใช่ตัวแปรประเภท Optional จะไม่สามารถมีค่าเป็น nil
ได้
เพื่อให้เวลาที่เราอ่านโค้ด สามารถรู้ได้ว่า เราต้อง ตรวจสอบหรือไม่ต้องตรวจสอบ nil
ซึ่งจะช่วยลดการเกิด runtime error รวมทั้งลดการเขียนแบบ defensive programming ที่มากเกินไป
Optional เป็น Type ใหม่ที่มี associated type เป็น type ต่าง ๆ เช่น String
ในการประกาศให้ตัวแปรเป็น Optional ให้เราประกาศเหมือนตัวแปรปกติ แต่ที่ Type เราจะใส่ ?
หรือ !
ลงท้าย เช่น
var payment: PaymentType?
var textField: UITextField!
ในการถอดค่าเพื่อเอา value ใน optional มาใช้ในรูปแบบปกติ เช่น การถอดจาก String?
เป็น String
หรือ String!
เป็น String
เรียกว่า unwraping ซึ่งวิธีการจะมีสิ่งที่เรียกว่า Optional Binding
ซึ่งก็คือ การทดสอบว่า nil
ไหมนั่นเอง จะมีหน้าตาประมาณนี้
let amount = "34"
if let total = Int(amount) {
print("Total items: \(total)")
} else {
print("Invalid total items")
}
ถ้าจากตัวอย่างจะเห็นว่า ในการแปลงค่าจาก 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 เหมือนกัน ต่างกันตรงที่การใช้ !
หมายความว่า ณ เวลาที่ใช้ผู้เขียนแน่ใจว่าค่าจะไม่เป็น nil
นั่นคือ เมื่อเราประกาศแบบ !
เราจะสามารถเขียนโค้ดเหมือนตัวแปรแบบปกติ คือ เราสามารถ assign ให้โดยไม่ต้องทำ unwrap ได้ แบบนี้
var total = 0
let amount: Int! = 5
total = total + amount
นั่นคือ เราสามารถเขียน total + amount
ได้เลยโดยที่ไม่ต้องทำแบบนี้
var total = 0
let amount: Int? = 5
if let amount = amount {
total = total + amount
}
การใช้ !
ต้องแน่ใจว่าเวลาที่ใช้ค่าตัวแปรนั้น จะต้องไม่มีค่าเป็น nil
เพราะถ้ามีค่าเป็น nil
การใช้ค่าโดยไม่ unwrap ก่อนจะทำให้เกิด runtime error และ application ของเราก็จะ crash
นอกจาก Optional Binding แล้ว เรายังมี optional chaining นั่นคือในบางครั้งเราก็ไม่จำเป็นต้องถอดจนครบทีละตัว แต่สนใจที่ผลลัพธ์สุดท้าย ให้เราใส่ ?
หรือ !
ไปตามจุดต่าง ๆ ใน statement เรา เช่น
if let roundedNumber = Double("123.45")?.rounded() {
}
ตัวอย่างนี้ จะเห็นว่าเราไม่ได้ unwrap Double?
ก่อนแล้วค่อย rounded()
ใน if
ในกรณีนี้เราใส่ ?
หลัง Double("123.45")
แล้ว rounded()
การทำแบบนี้ optional chaining ซึ่งการใส่ ?
จะยังทำให้ผลลัพธ์ทั้งหมดของ statement นี้ยังเป็น Double?
เราจึงยัง unwrap ด้วย optional binding ต่อด้วย if let
ถ้า Double("123.45")
ให้ผลลัพธ์เป็น nil
ฟังก์ชันrounded()
จะไม่ถูกเรียก และให้ผลลัพธ์เป็น nil
เลย
Last updated