Protokol Swift Kepatuhan opsional melalui Non-Opsional

Aug 18 2020

Saya memiliki protokol dengan properti opsional.

Sebagian besar tipe yang sesuai dengan protokol ini akan memiliki properti opsional yang cocok. Namun, seseorang memiliki properti non-opsional dengan tipe dan nama yang sama.

protocol SomeProtocol {
    var foo: Int? { get }
}

struct StructA: SomeProtocol {
    let foo: Int?
}

struct StructB: SomeProtocol {
    let foo: Int // Type 'StructB' does not conform to protocol 'SomeProtocol'
}

Menekan Xcode "Perbaiki - Apakah Anda ingin menambahkan rintisan protokol?" tombol menambahkan versi opsional properti, tetapi strukturnya sekarang memiliki nama variabel duplikat yang tidak valid:

struct StructB: SomeProtocol {
    let foo: Int
    var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}

Dalam { get }kasus -hanya, saya berasumsi bahwa ini akan "hanya bekerja" karena non-opsional selalu memenuhi batasan opsional, mirip dengan bagaimana Anda dapat mengembalikan non-opsional dalam fungsi dengan tipe pengembalian opsional. Namun ternyata bukan itu masalahnya.

Ini juga berfungsi sama untuk fungsi; sebuah protokol func bar() -> Int?tidak dipenuhi dengan jenis deklarasi yang sesuai func bar() -> Int.

Apakah ada cara untuk mengatasi masalah ini? Saya lebih suka untuk tidak mengganti nama variabel atau menambahkan getter perantara.

Apakah situasi ini telah dipertimbangkan untuk Swift? Apa alasan rasional untuk tidak mengizinkan non-opsional untuk memenuhi variabel protokol opsional?

Jawaban

pkamb Aug 19 2020 at 00:34

Jika protokol menyediakan implementasi default yang mengembalikan opsional:

protocol SomeProtocol {
    var foo: Int? { get }
}

extension SomeProtocol {
    var foo: Int? { return nil }
}

jenis yang sesuai protokol kemudian dapat memberikan versi non-opsional utama dari variabel / fungsi:

struct StructB: SomeProtocol {
    let foo: Int
}

Saya menemukan ini dibahas di forum Evolusi Swift:

Sekilas saya pikir ada aturan yang memungkinkan kita memenuhi persyaratan protokol dengan tipe non-opsional, tetapi ini mengakibatkan kesalahan. Hanya setelah penyelidikan lebih lanjut saya melihat bahwa implementasi default harus ada untuk 'jenis menimpa' persyaratan dengan versi non-opsional.

https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448

Tim Swift ini juga membahas tentang mengizinkan tipe non-opsional untuk memenuhi protokol nilai opsional:

Apakah masuk akal untuk mengizinkan pemenuhan persyaratan protokol dengan tipe non-opsional, seperti dengan init yang dapat gagal? (Mungkin dengan beberapa promosi opsional implisit.)

Ya, benar-benar! Kecuali untuk bagian di mana ini mengubah perilaku kode yang ada, jadi kita harus sangat berhati-hati. Ini dianggap sebagai bagian dari [SR-522]. Fungsi protokol tidak dapat memiliki hasil kovarian

yang dilacak di Stack Overflow di sini:

Mengapa persyaratan properti get-only dalam protokol tidak dapat dipenuhi oleh properti yang sesuai?