Swift Protocol Optionale Konformität über Non-Optional
Ich habe ein Protokoll mit einer optionalen Eigenschaft.
Die meisten Typen, die diesem Protokoll entsprechen, haben eine übereinstimmende optionale Eigenschaft. Man hat jedoch eine nicht-optionale Eigenschaft des gleichen Typs und Namens.
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'
}
Drücken Sie auf Xcodes "Fix - Do you want to add protocol stubs?" Schaltfläche fügt die optionale Version der Eigenschaft hinzu, aber die Struktur hat jetzt ungültige doppelte Variablennamen:
struct StructB: SomeProtocol {
let foo: Int
var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}
Im { get }-only-Fall hatte ich angenommen, dass dies "einfach funktionieren" würde, da das Nicht-Optionale immer die Einschränkungen des Optionalen erfüllt, ähnlich wie Sie ein Nicht-Optionales in einer Funktion mit einem optionalen Rückgabetyp zurückgeben können. Aber anscheinend ist das nicht der Fall.
Dies funktioniert auch für Funktionen; Die eines Protokolls func bar() -> Int?wird nicht durch einen konformen Typ erfüllt, der deklariert func bar() -> Int.
Gibt es eine Möglichkeit, dieses Problem zu umgehen? Ich würde es vorziehen, die Variablen nicht umzubenennen oder zwischengeschaltete Getter hinzuzufügen.
Wurde diese Situation für Swift berücksichtigt? Was ist der Grund dafür, nicht zuzulassen, dass eine nicht optionale Protokollvariable eine optionale Protokollvariable erfüllt?
Antworten
Wenn das Protokoll eine Standardimplementierung bereitstellt, die optional Folgendes zurückgibt:
protocol SomeProtocol {
var foo: Int? { get }
}
extension SomeProtocol {
var foo: Int? { return nil }
}
protokollkonforme Typen können dann eine überschreibende nicht-optionale Version der Variablen/Funktion bereitstellen:
struct StructB: SomeProtocol {
let foo: Int
}
Ich fand dies im Swift Evolution-Forum diskutiert:
Auf den ersten Blick dachte ich, es gibt eine Regel, die es uns erlaubt, Protokollanforderungen mit nicht optionalen Typen zu erfüllen, aber dies führte zu einem Fehler. Erst nach weiterer Untersuchung bemerkte ich, dass eine Standardimplementierung vorhanden sein muss, um die Anforderung mit einer nicht optionalen Version "irgendwie außer Kraft zu setzen".
https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448
Dieses Swift-Team erörtert auch, dass nicht optionale Typen Protokolle mit optionalen Werten erfüllen können:
Wäre es sinnvoll, die Erfüllung der Protokollanforderungen mit nicht optionalen Typen zuzulassen, wie z. B. mit ausfallbaren Initialisierungen? (Wahrscheinlich mit einer impliziten optionalen Beförderung.)
Ja, total! Abgesehen von dem Teil, in dem dies das Verhalten des vorhandenen Codes ändert, müssen wir also sehr vorsichtig damit sein. Dies wird als Teil von [SR-522] betrachtet. Protokollfunktionen können keine kovarianten Rückgaben haben
die auf Stack Overflow hier verfolgt wird:
Warum kann eine Get-Only-Eigenschaftsanforderung in einem Protokoll nicht durch eine konforme Eigenschaft erfüllt werden?