2015-09-30 1 views
11

Ich bin versucht, ein erzwungenes Protokoll-Erweiterung zu einer Struktur (Swift 2.0) und Empfangen der folgenden Compiler-Fehler anwenden:Protokollerweiterungen auf Structs Ursachen kompilieren Fehler ‚Self‘ beschränkt auf nicht-Protokolltyp

type 'Self' constrained to non-protocol type 'Foo'

struct Foo: MyProtocol { 
    let myVar: String 

    init(myVar: String) { 
     self.myVar = myVar 
    } 
} 

protocol MyProtocol { 
    func bar() 
} 

extension MyProtocol where Self: Foo { 
    func bar() { 
     print(myVar) 
    } 
} 

let foo = Foo(myVar: "Hello, Protocol") 
foo.bar() 

Ich kann diesen Fehler beheben, indem ich struct Foo zu class Foo ändere, aber ich verstehe nicht, warum das funktioniert. Warum kann ich nicht ein where Self: Constrained-Protokoll eine Struktur machen?

Antwort

16

Dies ist ein erwartetes Verhalten unter Berücksichtigung struct sind nicht dazu bestimmt, vererbt werden, die : Notation steht für.

Der richtige Weg zu erreichen, was Sie mögen so etwas wie Gleichheitszeichen wäre beschrieben:

extension MyProtocol where Self == Foo { 
    func bar() { 
     print(myVar) 
    } 
} 

Aber aus irgendeinem dummen Grund nicht wie kompilieren:

Same-type requirement makes generic parameter Self non-generic

Für was es wert ist , können Sie das gleiche Ergebnis mit den folgenden erreichen:

protocol FooProtocol { 
    var myVar: String { get } 
} 
struct Foo: FooProtocol, MyProtocol { 
    let myVar: String 
} 

protocol MyProtocol {} 
extension MyProtocol where Self: FooProtocol { 
    func bar() { 
    print(myVar) 
    } 
} 

wo FooProtocol ist gefälscht , die nur Foo verlängern sollte.

Viele Bibliotheken von Drittanbietern, die versuchen extend Standardbibliothek struct Typen (z. B. optional) verwendet eine Umgehung wie oben.

+0

Nun, das ist dann ärgerlich. Danke für die Antwort! – Benjohn

3

Ich lief gerade in dieses Problem auch. Obwohl auch würde ich ein besseres Verständnis mag, warum dies so ist, die Swift-Sprachreferenz (der Guide sagt nichts darüber) hat die folgenden Optionen aus dem Abschnitt Allgemeine Parameter:

Where Clauses

You can specify additional requirements on type parameters and their associated types by including a where clause after the generic parameter list. A where clause consists of the where keyword, followed by a comma-separated list of one or more requirements.

The requirements in a where clause specify that a type parameter inherits from a class or conforms to a protocol or protocol composition. Although the where clause provides syntactic sugar for expressing simple constraints on type parameters (for instance, T: Comparable is equivalent to T where T: Comparable and so on), you can use it to provide more complex constraints on type parameters and their associated types. For instance, you can express the constraints that a generic type T inherits from a class C and conforms to a protocol P as <T where T: C, T: P>.

So ‚Self‘ kann nicht eine Struktur sein oder emum scheint es, was eine Schande ist. Vermutlich gibt es hierfür einen sprachlichen Gestaltungsgrund. Die Compiler-Fehlermeldung könnte allerdings klarer sein.

0

Als Foo ein vorhandener Typ ist, könnten Sie einfach erweitern es auf diese Weise:

struct Foo { // <== remove MyProtocol 
    let myVar: String 

    init(myVar: String) { 
     self.myVar = myVar 
    } 
} 

// extending the type 
extension Foo: MyProtocol { 
    func bar() { 
     print(myVar) 
    } 
} 

Von The Swift Programming Language (Swift 2.2):

If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined.

Verwandte Themen