Der optionale Feldtyp entspricht nicht dem Protokoll in Swift 3

8

Ich habe eine Klasse mit einem optionalen Feld und einem nicht optionalen Feld, beide mit dem Typ AnotherClass und dem CustomProtocol :

%Vor%

Das Feld nonoptionalField ist vom Typ AnotherClass und entspricht CustomProtocol . p>

Auf der anderen Seite ist optionalField tatsächlich Optional & lt; AnotherClass & gt; und entspricht daher NICHT CustomProtocol :

%Vor%

Wie kann ich den Typ (nicht den Wert) der optionalField -Eigenschaft entfernen, sodass ich ihn mit seinem Protokoll CustomProtocol verknüpfen kann?

Mit anderen Worten, wie bekomme ich den umschlossenen Typ AnotherClass von Optional & lt; AnotherClass & gt; Typ?

BESCHRÄNKUNG:

Ich muss wirklich Swift-Reflection durch Mirror verwenden, und unglücklicherweise erlaubt die Eigenschaft .subjectType das Entpacken des optionalen Wrappertyps nicht. Optional & lt; AnotherClass & gt; bisher.

    
juliancadi 12.03.2017, 19:46
quelle

2 Antworten

4

Ich glaube nicht, dass es einen einfachen Weg gibt, dies zu tun, da wir derzeit nicht über generische Typen ohne ihre Platzhalter sprechen können - daher können wir nicht einfach auf Optional.Type umstellen.

Wir können auch nicht in Optional<Any>.Type umwandeln, da der Compiler nicht die gleichen automatischen Konvertierungen für Metatyp-Werte bereitstellt, die er für Instanzen bereitstellt (z. B. An Optional<Int> ist in eine Optional<Any> umwandelbar, aber eine Optional<Int>.Type ist nicht in Optional<Any>.Type ) umwandelbar.

Eine Lösung, wenn auch etwas hackig, wäre, ein Dummy-Protokoll zu definieren, das eine beliebige Optional -Instanz darstellt, unabhängig vom Typ Wrapped . Dann kann dieses Protokoll eine wrappedType -Anforderung definieren, um den Wrapped -Metatyp-Wert für den angegebenen Optional -Typ zu erhalten.

Zum Beispiel:

%Vor%

Nun, wenn fieldMirror.subjectType ein Optional<Wrapped>.Type ist, können wir es in OptionalProtocol.Type umwandeln und von dort den wrappedType metatype Wert erhalten. Dann können wir nach CustomProtocol Übereinstimmung suchen.

%Vor%

Dies bezieht sich nur auf eine einzelne Ebene der optionalen Verschachtelung, könnte aber leicht angepasst werden, um auf eine beliebige optionale Verschachtelungsebene anzuwenden, indem einfach wiederholt versucht wird, den resultierenden Metatyp-Wert auf OptionalProtocol.Type und dann auf wrappedType zu setzen Überprüfen auf CustomProtocol Konformität.

%Vor%     
Hamish 12.03.2017, 22:29
quelle
1

Das ist eine interessante Frage, aber nachdem ich eine Weile damit herumgespielt habe, glaubte ich früher (und wurde falsch korrigiert), dass dies nicht mit nativem Swift gelöst werden konnte, was jedoch möglicherweise durch @Hamish: s Antwort .

Das Ziel

Wir wollen, bedingt zur Laufzeit, den Wrapped type ( Optional<Wrapped> ) einer in Any eingepackten Instanz haben, ohne tatsächlich Wrapped zu kennen, nur wissend, dass Wrapped möglicherweise einem Protokoll entspricht; in Ihrem Beispiel CustomProtocol .

Die (nicht unüberwindbaren) Hindernisse

Es gibt einige Hindernisse, die uns daran hindern, eine Lösung für dieses Introspektionsproblem zu finden, nämlich zu testen, ob eine Instanz von Optional<Wrapped> , die in sich selbst in einer Instanz von Any eingeschlossen ist, einen Typ% enthält. co_de%, das einem bestimmten Protokoll entspricht (wobei Wrapped nicht bekannt ist). Insbesondere hindert es uns an einer allgemeinen Lösung, die sogar für den Fall, in dem der Wert, auf den man sich einlässt, Wrapped ist

Wie bereits in Ihrer Frage erwähnt, ist das erste Problem, dass in Optional<Wrapped>.none -Instanzen enthaltene Optionale nicht kovariant sind (Optionale selbst sind kovariant, aber das ist im speziellen Fall auch für zB einige Sammlungen vorhanden, während für benutzerdefinierte Wrapping-Typen das Standardverhalten von Nicht-Kovarianz-Holds). Daher können wir die Konformität des in Any eingeschlossenen Typs auf der optionalen Ebene vs Any nicht erfolgreich testen, auch wenn Optional<MyProtocol> selbst mit Wrapped übereinstimmt.

%Vor%

Das zweite Problem ist etwas überlappend: Wir können eine MyProtocol -Instanz, die ein optionales Element enthält, nicht direkt auf den optionalen Typ oder (durch Nicht-Kovarianz) auf einen optionalen Typ eines Protokolls umwandeln, dem der umschlossene Typ entspricht. Zum Beispiel:

%Vor%

Nun können wir dies umgehen, indem wir ein wertbindendes Muster verwenden:

%Vor%

Aber das ist nur ein Workaround, der hilft, falls Any über nicht foo ist, während wenn nil ist foo , wir keine binded-Instanz haben, auf der wir Typ & amp; Protokollkonformitätsanalyse.

%Vor%

Ich habe mit ein paar verschiedenen Ansätzen gespielt, aber am Ende komme ich auf das Problem zurück, dass für eine optionale nil -bewertete Instanz, die in nil eingewickelt ist, auf Any zugreift (ohne es zu wissen: zB als Metatyp) scheint nicht möglich. Wie in @Hamish: s Antwort gezeigt, ist dies jedoch nicht unüberwindbar und kann durch Hinzufügen eines zusätzlichen Protokolls gelöst werden Ebene über Wrapped .

Ich werde meine nicht ganz im Ziel liegenden Versuche jedoch oben lassen, da die Techniken und die Diskussion für Leser dieses Themas aufschlussreich sein können, selbst wenn sie es nicht geschafft haben, das Problem zu lösen. p>     

dfri 12.03.2017 21:58
quelle

Tags und Links