2016-05-05 5 views
0

Kann mir jemand erklären, warum das nicht funktioniert?Der generische Parameter T konnte nicht abgeleitet werden. Factory-Methoden

Ich habe eine Klasse mit Factory-Methoden wie folgt aus:

public class NetworkTask<T> { 

    var request: URLRequest 

    var completionHandler: NetworkResponse<T> -> Void 

    init(request: URLRequest, completionHandler: NetworkResponse<T> -> Void) { 

     self.request = request 
     self.completionHandler = completionHandler 
    } 

    static func dataResponseTaskWithRequest(request: URLRequest, completionHandler: NetworkResponse<NSData> -> Void) -> NetworkTask<NSData> { 

     return NetworkTask<NSData>(request: request, completionHandler: completionHandler) 
    } 

    static func mappedObjectResponseTaskWithRequest<MappedType>(request: URLRequest, completionHandler: NetworkResponse<MappedType> -> Void) -> NetworkTask<MappedType> { 

     return NetworkTask<MappedType>(request: request, completionHandler: completionHandler) 
    } 
} 

Dann, nach glücklich zu wissen, dass es kompiliert, gehe ich eine Aufgabe wie diese zu erstellen:

let task = NetworkTask.dataResponseTaskWithRequest(URLRequest()) { (response) in 

    } 

Nope ...

Rischer Parameter T nicht geschlossen werden konnte

Warte, ich kann es eindeutig ableiten, die Methode gibt NetworkTask<NSData> zurück, also ist T NSData.

Ok ... dann, vielleicht so?

let task: NetworkTask<NSData> = NetworkTask.dataResponseTaskWithRequest(URLRequest()) { (response) in 

} 

Nope ...

nicht 'dataResponseTaskWithRequest' mit einem Argument Liste vom Typ '(URLRequest, (_) -> _)' Kann aufrufen

Ok, vielleicht die andere Methode:

let task = NetworkTask.mappedObjectResponseTaskWithRequest(URLRequest()) { (response: NetworkResponse<String>) in 

} 

Nope ...

Wert kann nicht vom Typ umwandeln '(NetworkResponse) ->()' zu erwarten Argument Typ 'NetworkResponse < _> -> Void'

ich eindeutig etwas hier, weil der Compiler fehlt kann werden müssen‘ Ich habe so viele Fehler. Hat jemand eine Ahnung?

Antwort

3

NetworkTask<T> ist der Typ, nicht NetworkTask. Das heißt, der Parameter T ist in der Klasse enthalten und alles, was Sie mit dieser Klasse tun, um auch auf ihre Klassenmethoden zugreifen zu können, erfordert die Beschreibung dieses Typs. Wenn die T nicht in der Methodendeklaration enthalten ist, die Ihnen den Compilerfehler gibt, gibt es keine Klasse NetworkTask, die alle Klassenmethoden enthalten würde, bei denen der Typparameter nicht enthalten ist - stellen Sie sich stattdessen vor, dass die Methode auf allen ist Klassen NetworkTask<T> für jeden Wert von T. Dies ist ähnlich wie in C++, wo das Entsprechende auch als "Template" bezeichnet wird, was bedeutet, dass Ihre Klassendeklaration mit generischen Typparametern als Vorlage für das wörtliche Kompilieren verschiedener Klassen verwendet wird. Dies ist anders als zum Beispiel in Java, wo die Generics-Syntax nur zum Kompilieren von Zucker mit Typ-Löschen verwendet wird (Sie könnten dort tatsächlich die Klassenmethode aufrufen - nur eine Klasse existiert in diesem Fall wirklich).

Hier ist ein minimales Beispiel diesen etwas mehr Demo:

class A<T> { 
    class func foo() { 
    } 

    class func bar(t:T) -> Void { 
    } 
} 

class B {} 

A.foo() // this gives an error because the type cannot be inferred. 

A.bar(1) // this works fine without compiler errors as the integer literal type can be inferred there. 

Im Beispiel oben genannten Fall würde ein feiner sein zum Beispiel aufgerufen mit:

A<IntegerLiteralType>.foo()

Sie sollten vielleicht darüber nachdenken ob die Methoden in diesem Fall zu der Klasse gehören, die diesen Typparameter T hat, oder ob sie etwas anderes als Empfänger haben sollen (oder auch, ob es sich um freie Funktionen handelt?).

+0

Das ist absolut richtig. In meinem Fall schlägt es den Punkt, also habe ich eine TaskBuilder-Klasse mit den statischen Methoden erstellt. Dieser Ansatz scheint gut zu funktionieren. Ich danke Ihnen sehr für Ihre Antwort. – diegomontoyas

Verwandte Themen