Ja. Aber die Antwort ist ein bisschen komisch. Der erste Teil macht eine vernünftige Menge an Sinn; Der zweite Teil ist einfach total komisch. Lass uns hindurchgehen.
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
Die richtige Überlastung für print
zu wählen ist bei der Kompilierung entschieden, nicht Runtime. Das ist die Sache, die die Menschen am meisten verwirrt. Sie möchten Swift wie JavaScript behandeln, wo alles dynamisch ist. Swift ist gerne statisch, weil es dann sicherstellen kann, dass Ihre Typen richtig sind und viele Optimierungen durchführen können (und Swift liebt, um Compiler-Optimierungen durchzuführen). Also, Kompilierzeit, welcher Typ ist args
? Nun, es ist T
. Ist T
bekannt als Printable
? Nein ist es nicht. So verwendet es die nicht Printable
Version.
Aber wenn Swift spezialisiert Generic
mit PrintableObj
, weiß es nicht an diesem Punkt, dass es Printable
ist? Konnte der Compiler zu diesem Zeitpunkt keine andere Version von display
erstellen? Ja, wenn wir zur Kompilierzeit jeden Aufrufer kennen würden, der jemals von dieser Funktion existieren würde, und dass keiner von ihnen jemals zu Printable
erweitert würde (was in einem komplett anderen Modul passieren könnte). Es ist schwierig, dies zu lösen, ohne viele seltsame Eckenfälle zu erzeugen (wo sich beispielsweise interne Dinge anders verhalten als öffentliche Dinge), ohne Swift dazu zu zwingen, proaktiv jede mögliche Version von display
zu erzeugen, die von irgendeinem zukünftigen Anrufer benötigt wird. Swift mag sich mit der Zeit verbessern, aber das ist ein schweres Problem, denke ich. (Swift erleidet bereits Leistungseinbußen, sodass öffentliche Generika ohne Zugriff auf den ursprünglichen Quellcode spezialisiert werden können. Dies würde dieses Problem noch komplizierter machen.)
OK, also bekommen wir das. T
ist nicht Printable
. Aber was, wenn wir einen Typ hatten, der war eindeutig Printable
, dass wir zur Kompilierzeit wussten und in dieser Funktion lebten? Würde es dann funktionieren?
func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
Oh so nah ... aber nicht ganz. Diese fast funktioniert. Die if-let
macht eigentlich genau das, was Sie wollen. wird zugewiesen. Es ist Printable
. Aber es ruft immer noch die nicht druckbare Funktion auf. ?!?!?!?!
Dies ist ein Ort, den ich persönlich denke, dass Swift gerade gerade gebrochen ist und große Hoffnungen haben, dass es behoben wird. Es könnte sogar ein Fehler sein. Das Problem ist, dass Printable
selbst nicht Printable
entspricht. Ja, ich verstehe es auch nicht, aber da gehst du hin. Also müssen wir etwas machen, das Printable
entspricht, um die richtige Überlastung zu bekommen. Wie immer, type erasers zur Rettung.
struct AnyPrintable: Printable {
let value: Printable
}
struct Generic<T> {
var args: T
func display() {
if let p = args as? Printable {
print(Printer.print(AnyPrintable(value: p)))
} else {
print(Printer.print(args))
}
}
}
Und dies wird so drucken, wie Sie wollten. (Unter der Annahme, dass Printable
einige Methoden erfordern, würden Sie nur diese Methoden zum AnyPrintable
Art Radiergummi hinzufügen.)
Natürlich ist die richtige Antwort ist nicht generisch Überlastungen auf diese Weise in Printer
zu verwenden. Es ist einfach viel zu verwirrend und zerbrechlich. Es sieht so gut aus, aber es explodiert die ganze Zeit.
Vielen Dank für diese Information. Es sieht komplex aus, um in das zu passen, was ich gerade versuche. https://github.com/RahulKatariya/Reactofire/blob/develop/ReactofireTests/Models/GenericResponse/_GenericResponse.swift .. Ich versuche, GenericResponseString und GenericResponsePerson Tests bestanden zu machen. –
Viel Glück ... Ich habe viel experimentiert mit diesen super-cleveren/magischen Ansätzen zu grundlegenden Problemen. Persönlich fand ich, dass ein paar Zeilen einfachen Codes, auch wenn Sie gelegentlich ein paar mühsame Zeilen hier oder dort wiederholen müssen, viel besser funktionieren, besonders wenn es Zeit ist zu debuggen (ich bewache einfach mein JSON Parsing jetzt; so viel einfacher). Es ist nicht so aufregend, aber es hat viel besser in meinen Projekten funktioniert. Aber viel Glück für diejenigen, die immer noch die Grenze erkunden! Es macht Spaß, aber es gibt eine Menge Frustration wie diese. –