Memberikan nilai default untuk Opsional di Swift?

141

Ungkapan untuk berurusan dengan opsional di Swift tampaknya terlalu banyak bertele-tele, jika semua yang ingin Anda lakukan adalah memberikan nilai default dalam kasus di mana nihil:

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

yang melibatkan duplikasi kode yang tidak perlu, atau

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

yang membutuhkan unwrappedValuetidak konstan.

Opsi Scala's monad (yang pada dasarnya ide yang sama dengan Swift's Optional) memiliki metode getOrElseuntuk tujuan ini:

val myValue = optionalValue.getOrElse(defaultValue)

Apakah saya melewatkan sesuatu? Apakah Swift sudah memiliki cara yang kompak untuk melakukannya? Atau, jika gagal, apakah mungkin untuk mendefinisikan getOrElseekstensi untuk Opsional?

Wes Campaigne
sumber

Jawaban:

289

Memperbarui

Apple sekarang telah menambahkan operator penggabungan:

var unwrappedValue = optionalValue ?? defaultValue

Operator ternary adalah teman Anda dalam hal ini

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

Anda juga dapat memberikan ekstensi sendiri untuk enum Opsional:

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

Maka Anda bisa melakukan:

optionalValue.or(defaultValue)

Namun, saya sarankan tetap berpegang pada operator ternary karena pengembang lain akan memahami itu lebih cepat tanpa harus menyelidiki ormetode ini

Catatan : Saya memulai modul untuk menambahkan pembantu umum seperti ini orpada Optionalke cepat.

drewag
sumber
kompiler saya menunjukkan kepada saya bahwa tipe unwrappedValueini masih merupakan tipe opsional untuk kasus ini di Swift 1.2: var unwrappedValue = optionalValue ? optionalValue! : defaultValue(xcode 6 beta 4). Apakah ini sudah berubah?
SimplGy
2
Saya salah pada versi saya. Saya di 6.4. Berhati-hatilah: ??perilaku inferensi tipe standar adalah mengembalikan opsional, yang biasanya bukan yang Anda inginkan. Anda dapat mendeklarasikan variabel sebagai non-opsional dan ini berfungsi dengan baik.
SimplGy
29

Pada Agustus 2014, Swift memiliki operator penggabungan (??) yang memungkinkan. Misalnya, untuk myOptional String opsional, Anda dapat menulis:

result = myOptional ?? "n/a"
Mire
sumber
4

jika Anda menulis:

let result = optionalValue ?? 50

dan optionalValue != nilkemudian resultakan optionalterlalu dan Anda akan perlu membukanya di masa depan

Tetapi Anda dapat menulis operator

infix operator ??? { associativity left precedence 140 }

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

Sekarang kamu bisa:

 let result = optionalValue ??? 50

Dan kapan optionalValue != nilitu resultakan terjadiunwraped

UnRewa
sumber
3

Tampaknya ini berhasil

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

namun kebutuhan untuk melakukan cast value as Tadalah hack yang jelek. Idealnya, harus ada cara untuk menegaskan bahwa Titu sama dengan jenis yang terdapat dalam Opsional. Seperti berdiri, ketik set menyimpulkan Tberdasarkan parameter yang diberikan untuk getOrElse, dan kemudian gagal saat runtime jika ini tidak cocok dengan Opsional dan Opsional adalah nihil:

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
Wes Campaigne
sumber
Anda tidak perlu menentukan Tuntuk metode ini. Itu benar-benar mengesampingkan yang ada Tdari Opsional. Anda bisa melakukannya: func getOrElse(defaultValue: T) -> Tlalu T mengacu pada tipe nilai real dari opsional dan Anda tidak perlu mengetik memeriksanya
drewag
Terima kasih! Saya menyimpulkan dengan tepat dari paruh kedua tanggapan Anda. Apakah ada cara untuk memeriksa definisi Opsional untuk mengetahui bahwa jenis generik didefinisikan seperti Titu? (Di luar hanya dengan asumsi berdasarkan konvensi)
Wes Campaigne
Jika Anda mengeklik perintah di Optionaldalam Xcode, Anda akan melihat bahwa itu didefinisikan sebagaienum Optional<T>
drewag
Oh, bagus sekali. Saya seharusnya sudah menebak. Definisi di sana akan bermanfaat; ada banyak hal yang belum ada dalam dokumentasi. Terima kasih lagi.
Wes Campaigne