ระบุค่าเริ่มต้นสำหรับตัวเลือกใน Swift หรือไม่


141

สำนวนสำหรับการจัดการกับตัวเลือกใน Swift ดูเหมือนจะละเอียดเกินไปหากสิ่งที่คุณต้องการทำคือให้ค่าเริ่มต้นในกรณีที่ไม่มีค่า:

if let value = optionalValue {
    // do something with 'value'
} else {
    // do the same thing with your default value
}

ซึ่งเกี่ยวข้องกับการทำซ้ำรหัสโดยไม่จำเป็นหรือ

var unwrappedValue
if let value = optionalValue {
    unwrappedValue = value
} else {
    unwrappedValue = defaultValue
}

ซึ่งต้องunwrappedValueไม่คงที่

ตัวเลือกของ Scala monad (ซึ่งโดยพื้นฐานแล้วเป็นความคิดเดียวกันกับทางเลือกของ Swift) มีวิธีการgetOrElseสำหรับจุดประสงค์นี้:

val myValue = optionalValue.getOrElse(defaultValue)

ฉันพลาดอะไรไปรึเปล่า? Swift มีวิธีการที่กะทัดรัดในการทำเช่นนั้นหรือไม่? หรือล้มเหลวนั้นเป็นไปได้ที่จะกำหนดgetOrElseในส่วนขยายสำหรับตัวเลือกหรือไม่


คำตอบ:


289

ปรับปรุง

Apple ได้เพิ่มผู้ดำเนินการรวมตัวกัน:

var unwrappedValue = optionalValue ?? defaultValue

ผู้ประกอบการที่ประกอบไปด้วยคือเพื่อนของคุณในกรณีนี้

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

คุณสามารถให้ส่วนขยายของคุณเองสำหรับ enum เพิ่มเติม:

extension Optional {
    func or(defaultValue: T) -> T {
        switch(self) {
            case .None:
                return defaultValue
            case .Some(let value):
                return value
        }
    }
}

จากนั้นคุณสามารถทำได้:

optionalValue.or(defaultValue)

อย่างไรก็ตามฉันขอแนะนำให้ติดกับผู้ประกอบการที่ประกอบไปด้วยนักพัฒนาคนอื่นจะเข้าใจได้เร็วกว่าโดยไม่ต้องตรวจสอบorวิธีการ

หมายเหตุ : ผมเริ่มโมดูลที่จะเพิ่มผู้ช่วยเหมือนกันเช่นนี้orในOptionalการที่รวดเร็ว


complier ของฉันแสดงให้ฉันเห็นว่าประเภทของประเภทunwrappedValueนี้ยังคงเป็นตัวเลือกสำหรับกรณีนี้ใน Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4) สิ่งนี้มีการเปลี่ยนแปลงหรือไม่?
SimplGy

2
ฉันผิดรุ่น ฉันอายุ 6.4 ปี ระวัง: ??พฤติกรรมการอนุมานค่าเริ่มต้นคือมันส่งกลับทางเลือกซึ่งไม่ใช่สิ่งที่คุณต้องการโดยทั่วไป คุณสามารถประกาศตัวแปรเป็นแบบไม่บังคับและใช้ได้ดี
SimplGy

29

ตั้งแต่เดือนสิงหาคม 2014 Swift มีผู้ดำเนินการรวมตัวกัน (??) ที่อนุญาตสิ่งนั้น ตัวอย่างเช่นสำหรับ String myOptional ที่เป็นตัวเลือกคุณสามารถเขียน:

result = myOptional ?? "n/a"

4

ถ้าคุณเขียนว่า:

let result = optionalValue ?? 50

และ optionalValue != nilจากนั้นก็resultจะมีoptionalมากเกินไปและคุณจะต้องแกะมันในอนาคต

แต่คุณสามารถเขียนโอเปอเรเตอร์ได้

infix operator ??? { associativity left precedence 140 }

func ???<T>(optLeft:T?, right:T!) -> T!
{
    if let left = optLeft
    {
        return left
    }
    else { return right}
}

ตอนนี้คุณสามารถ:

 let result = optionalValue ??? 50

และเมื่อ optionalValue != nilนั้น resultจะเป็นอย่างไรunwraped


3

ดูเหมือนว่าจะทำงานต่อไปนี้

extension Optional {
    func getOrElse<T>(defaultValue: T) -> T {
        if let value = self? {
            return value as T
        } else {
            return defaultValue
        }
    }
}

อย่างไรก็ตามความจำเป็นในการร่ายvalue as Tเป็นแฮ็คที่น่าเกลียด เป็นการดีที่ควรมีวิธีการยืนยันว่าTเป็นประเภทเดียวกับที่มีอยู่ในตัวเลือก ในขณะที่มันอยู่ให้พิมพ์ชุดการอนุมานTโดยอิงตามพารามิเตอร์ที่กำหนดให้กับ getOrElse แล้วล้มเหลวขณะรันไทม์หากสิ่งนี้ไม่ตรงกับทางเลือกและตัวเลือกไม่เป็นศูนย์:

let x: Int?

let y = x.getOrElse(1.414) // y inferred as Double, assigned 1.414

let a: Int? = 5

let b: Double = a.getOrElse(3.14) // Runtime failure casting 5 to Double

คุณไม่จำเป็นต้องระบุTวิธีการ ที่จริงแทนที่ที่มีอยู่Tจากตัวเลือก คุณก็สามารถทำได้: func getOrElse(defaultValue: T) -> Tแล้ว T หมายถึงชนิดของมูลค่าที่แท้จริงของตัวเลือกและคุณไม่ต้องพิมพ์ตรวจสอบ
drewag

ขอบคุณ! ฉันอนุมานอย่างชัดเจนว่าจากช่วงครึ่งหลังของการตอบกลับของคุณ มีวิธีในการตรวจสอบคำจำกัดความของตัวเลือกที่จะรู้ว่าประเภททั่วไปมีการกำหนดไว้Tในที่? (เกินกว่าการคาดเดาตามการประชุม)
Wes Campaigne

หากคุณคลิกคำสั่งOptionalภายใน Xcode คุณจะเห็นว่ามันถูกกำหนดเป็นenum Optional<T>
drewag

โอ้เยี่ยมมาก ฉันควรจะเดา คำจำกัดความในนั้นจะมีประโยชน์ มีหลายสิ่งที่ยังไม่ได้อยู่ในเอกสาร ขอบคุณอีกครั้ง.
Wes Campaigne
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.