2014-11-11 7 views
15

Ho il seguente protocollo e una classe che si conforma ad esso:Impossibile creare una matrice di tipi conformi ad un protocollo a Swift

protocol Foo{ 
    typealias BazType 

    func bar(x:BazType) ->BazType 
} 


class Thing: Foo { 
    func bar(x: Int) -> Int { 
     return x.successor() 
    } 
} 

Quando provo a creare un array di Foos, ottengo un errore dispari:

var foos: Array<Foo> = [Thing()] 

Protocol Foo can only be used as a generic constraint because it has Self or associated type requirements.

OK, quindi può essere utilizzato solo se ha un requisito tipo associato (che lo fa), ma per qualche motivo si tratta di un errore ?? WTF ?!

Non sono sicuro Capisco perfettamente quello che il compilatore sta cercando di dirmi ...

+0

possibile duplicato (http://stackoverflow.com/questions/26267597/cannot-assign-class-instance-to -its-protocol-type) – Antonio

risposta

13

Diciamo che, se potessimo mettere un esempio di Thing in una matrice foos, che cosa accadrà?

protocol Foo { 
    typealias BazType 

    func bar(x:BazType) -> BazType 
} 

class Thing: Foo { 
    func bar(x: Int) -> Int { 
     return x.successor() 
    } 
} 

class AnotherThing: Foo { 
    func bar(x: String) -> String { 
     return x 
    } 
} 

var foos: [Foo] = [Thing()] 

Perché AnotherThing conforme alle Foo troppo, in modo che possiamo metterla in foos anche.

foos.append(AnotherThing()) 

Ora abbiamo afferrare un foo da foos in modo casuale.

let foo = foos[Int(arc4random_uniform(UInt32(foos.count - 1)))] 

e ho intenzione di chiamare il metodo bar, mi puoi dire che devo inviare una stringa o un numero intero a bar?

foo.bar("foo") o foo.bar(1)

Swift non può.

Quindi può essere utilizzato solo come un vincolo generico.

Quale scenario richiede un protocollo come questo?

Esempio: [? Impossibile assegnare un'istanza di classe al suo tipo di protocollo]

class MyClass<T: Foo> { 
     let fooThing: T? 

     init(fooThing: T? = nil) { 
       self.fooThing = fooThing 
     } 

     func myMethod() { 
       let thing = fooThing as? Thing // ok 
       thing?.bar(1) // fine 

       let anotherThing = fooThing as? AnotherThing // no problem 
       anotherThing?.bar("foo") // you can do it 

       // but you can't downcast it to types which doesn't conform to Foo 
       let string = fooThing as? String // this is an error 
     } 
} 
1

Ho giocato con il codice cercando di capire come implementare il protocollo. Ho scoperto che non è possibile utilizzare Typealias come un tipo generico perché è solo un alias non un tipo di per sé. Quindi se dichiari le tipealie al di fuori del tuo protocollo e della tua classe, puoi usarlo efficacemente nel tuo codice senza alcun problema.

Nota: il Typealias ha il tipo Int nella sua dichiarazione, in questo modo si può sempre utilizzare l'alias al posto del tipo Int e usare tutti i suoi metodi e le funzioni associate.

Ecco come faccio funzionare:

typealias BazType = Int 

protocol Foo{ 
    func bar(x:BazType) -> BazType 
} 

class Thing: Foo { 
    func bar(x: BazType) -> BazType { 
    return x.successor() 
    } 
} 

let elements: Array<Foo> = [Thing(), Thing()] 
+0

in questo codice BazType è solo Int e non un tipo di variabile. –

Problemi correlati