2015-07-22 4 views
7

Code Folgende:Protokoll zugeordnet Typ typealias Zuordnung Kompilierungsfehler

protocol SomeProtocol { 
    typealias SomeType = Int // used typealias-assignment 

    func someFunc(someVar: SomeType) 
} 

class SomeClass: SomeProtocol { 
    func someFunc(someVar: SomeType) { 
     print(someVar) 
    } 
} 

gibt Fehler bei der Kompilierung:

Use of undeclared type 'SomeType'

Hinzufügen, sagen typealias SomeType = Double, um die SomeClass den Fehler behebt.

Die Frage ist, was ist der Punkt Typalias-Zuweisung Teil (was optional BTW) des Protokolls zugeordneten Typ Erklärung obwohl?

Antwort

5

In diesem Fall wird die Zuordnung von Int zum typealias ist keine Zuordnung gleich, weil sie von Ihrem Conforming Typ außer Kraft gesetzt wird:

// this declaration is equal since you HAVE TO provide the type for SomeType 
protocol SomeProtocol { 
    typealias SomeType 

    func someFunc(someVar: SomeType) 
} 

Eine solche Zuordnung liefert ein Standardtyp für SomeType, der von Ihrer Implementierung in SomeClass überschrieben wird, aber es ist besonders nützlich für Protokollerweiterungen:

protocol Returnable { 
    typealias T = Int // T is by default of type Int 
    func returnValue(value: T) -> T 
} 

extension Returnable { 
    func returnValue(value: T) -> T { 
     return value 
    } 
} 

struct AStruct: Returnable {} 

AStruct().returnValue(3) // default signature: Int -> Int 

Sie erhalten die Funktion kostenlos nur, indem Sie das Protokoll ohne Angabe des Typs T erfüllen. Wenn Sie einen eigenen Typ festlegen möchten, schreiben Sie typealias T = String // or any other type in den Strukturkörper.

Einige zusätzliche Hinweise zum Codebeispiel bereitgestellt

Sie löste das Problem, weil Sie es explizit gemacht, welche Art der Parameter hat. Swift folgert auch Ihre verwendete Art:

class SomeClass: SomeProtocol { 
    func someFunc(someVar: Double) { 
     print(someVar) 
    } 
} 

So SomeType des Protokolls geschlossen wird Double zu sein.

Ein anderes Beispiel, wo Sie diese SomeType in der Klassendeklaration zu dem Protokoll bezieht sich nicht sehen können:

class SomeClass: SomeProtocol { 
    typealias Some = Int 
    func someFunc(someVar: Some) { 
     print(someVar) 
    } 
} 

// check the type of SomeType of the protocol 
// dynamicType returns the current type and SomeType is a property of it 
SomeClass().dynamicType.SomeType.self // Int.Type 
// SomeType gets inferred form the function signature 

Wenn Sie jedoch, dass, wie etwas zu tun:

protocol SomeProtocol { 
    typealias SomeType: SomeProtocol 

    func someFunc(someVar: SomeType) 
} 
zu

SomeType hat vom Typ SomeProtocol sein, der für eine explizitere Abstraktion und mehr statischen Code verwendet werden kann, während dies:

protocol SomeProtocol { 
    func someFunc(someVar: SomeProtocol) 
} 

würde dynamisch gesendet werden.

+0

Schau, ich habe niemanden gebeten zu antworten, warum das Erklären von Typalias innerhalb der Klasse den Fehler behebt. Das hatte ich erkannt, bevor ich dieses Thema erstellt habe. Ich fragte, was ist die praktische Anwendung von Typalie Zuweisung innerhalb Protokoll. Um zu paraphrasieren, welche spezifischen Einschränkungen diese Funktionalität behebt? – mesmerizingr

+0

@mesmerizingsnow Das war nur zusätzliche Informationen. Aber ich gab auch die Antwort: Eine Zuweisung hat keine Auswirkung auf das Verhalten wie keine Zuweisung ("typealias SomeType = Int" ist gleich "typealias SomeType") – Qbyte

+0

Ich habe diese Antwort empirisch erhalten. Haben Sie etwas, um Ihre Antwort zu sichern, sagen Sie Links zu developer.apple.com Foren oder ein Zitat aus einem Blog, Twitter oder etwas? – mesmerizingr

1

Es gibt great article, die Ihnen tatsächlich die Antwort auf Ihre Frage gibt. Ich empfehle jedem, es zu lesen, um in Typ-Aliase und etwas fortgeschrittenere Sachen zu kommen, die auftauchen, wenn Sie es verwenden.

Citation von der Website:

Conceptually, there is no generic protocols in Swift. But by using typealias we can declare a required alias for another type.

+0

In dem Artikel sie typealias Zuordnung nicht genutzt. Sie verwendeten zwar eine Vererbungsklausel, aber das beantwortet meine Frage nicht. – mesmerizingr

5

Es gibt einige großartige Informationen in der Dokumentation zu "associated types" in Protokollen.

Ihre Verwendung ist reichlich in der gesamten Standard-Bibliothek, die für ein Beispiel SequenceType Protokollreferenz, die ein typealias für Generator erklärt (und gibt an, dass es zu GeneratorType entspricht). Dadurch kann die Protokolldeklaration auf diesen Alias-Typ verweisen.

In Ihrem Fall, wo Sie typealias SomeType = Int verwendet, vielleicht das, was Sie war gemeint „Ich möchte Sometype zu Integer-ähnliches Verhalten gezwungen werden, weil mein Protokoll Methoden auf diesem Zwang abhängen“ - in diesem Fall sollten Sie Verwenden Sie in Ihrem Protokoll typealias SomeType: IntegerType, und weisen Sie dann in Ihrer Klasse einen Typ diesem Alias ​​zu, der IntegerType entspricht.

UPDATE

Nach einem Fehler w/Apple auf dieser Öffnung ist und hatte umfangreiche Diskussion um ihn herum, ich habe zu einem Verständnis kommen, was die Basis Problem im Herzen dieser ist:

, wenn sie ein Protokoll entsprechen, Sie zu einem zugehörigen Typ nicht direkt beziehen können, die nur

(Anmerkung, howe innerhalb dieses Protokolls erklärt wurden ver, dass, wenn erstreckt ein Protokoll der zugehörige Typ verfügbar ist, wie man erwarten würde)

So in Ihrem ersten Codebeispiel:

protocol SomeProtocol { 
    typealias SomeType = Int 
    func someFunc(someVar: SomeType) 
} 

class SomeClass: SomeProtocol { 
    func someFunc(someVar: SomeType) { // use of undeclared type "SomeType" 
     print(someVar) 
    } 
} 

... der Fehler erneut: „Verwendung von nicht angemeldeter Typ“ist richtig, Ihre Klasse SomeClass hat nicht den Typ SomeType

jedoch erklärt, eine Erweiterung SomeProtocol Zugriff auf den zugehörigen Typ hat, und kann ihn bei einer Implementierung bereitstellt:

(beachten Sie, dass diese where Klausel, um die Anforderung an den zugehörigen Typ zu definieren, unter Verwendung eines erfordert)

protocol SomeProtocol { 
    typealias SomeType = Int 
    func someFunc(someVar: SomeType) 
} 

extension SomeProtocol where SomeType == Int { 
    func someFunc(someVar: SomeType) { 
     print("1 + \(someVar) = \(1 + someVar)") 
    } 
} 

class SomeClass: SomeProtocol {} 

SomeClass().someFunc(3) // => "1 + 3 = 4" 
+0

In meinem Fall habe ich die Int-Zuweisung verwendet, um diese Funktionalität zu testen. Ich saß auf meinem Laptop und las "Language Reference" der offiziellen Apple Swift Programming Guide-Referenz, kam zum Abschnitt "Declaration" und fand einen Link zur Protokolldeklaration mit Link zur zugehörigen Typdeklarationssyntax. Und da habe ich festgestellt, dass man bei der Deklaration von Typaliases die Typalias-Zuweisung verwenden kann. Obwohl es optional ist. – mesmerizingr