2014-10-24 11 views
5

Dato:Come definire una matrice di oggetti conformi a un protocollo?

protocol MyProtocol { 
    typealias T 
    var abc: T { get } 
} 

E una classe che implementa MyProtocol:

class XYZ: MyProtocol { 
    typealias T = SomeObject 
    var abc: T { /* Implementation */ } 
} 

Come posso definire un array di oggetti conformi alle MyProtocol?

var list = [MyProtocol]() 

esprime (insieme con una tonnellata di SourceKit blocca) il seguente errore:

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

Anche se il typealias è infatti definito in MyProtocol.

C'è un modo per avere un elenco di oggetti conforme a un protocollo E con un vincolo generico?

+0

possibile duplicato di [Utilizzo di protocolli come tipi di array e parametri di funzione in swift] (http://stackoverflow.com/questions/24888560/usage-of-protocols-as-array-types-and-function-parameters- in-swift) – Paulw11

+0

@ Paulw11 Il mio male, ho completamente perso quella. – erudel

risposta

3

Il problema riguarda l'utilizzo della controparte generica per i protocolli, digitare alias. Sembra strano, ma se si definisce un alias di tipo, non si può usare il protocollo come tipo, il che significa che non si può dichiarare una variabile di quel tipo di protocollo, un parametro di funzione, ecc. E non si può usarlo come oggetto generico di un array.

Come si dice l'errore, l'unico utilizzo che è possibile fare è come un vincolo generico (come in class Test<T:ProtocolWithAlias>).

Per dimostrare che, è sufficiente rimuovere le typealias dal protocollo (nota, questo è solo per dimostrare, non è una soluzione):

protocol MyProtocol { 
    var abc: Int { get } 
} 

e modificare il resto del codice di esempio di conseguenza:

class XYZ: MyProtocol { 
    var abc: Int { return 32 } 
} 

var list = [MyProtocol]() 

Noterai che funziona.

Probabilmente siete più interessati a come risolvere questo problema. Non riesco a pensare a qualsiasi soluzione elegante, appena il seguente 2:

  • rimuovere le typealias dal protocollo e sostituirla con TAnyObject (soluzione di brutto !!)
  • girare il protocollo in una classe (ma questo è non è una soluzione che funziona in tutti i casi)

ma come si può sostenere, non mi piace nessuno di loro. L'unico suggerimento che posso fornire è quello di ripensare al tuo design e capire se puoi usare un modo diverso (cioè non usare un protocollo tipografico) per ottenere lo stesso risultato.

+0

Questo ha senso se ci pensi. Poiché il tipo di ritorno di abc non è noto in fase di compilazione, non è possibile utilizzare in modo affidabile i risultati in modo sicuro. Un array di MyProtocol non ha senso perché non tutti hanno la stessa funzionalità. –

+0

@David: Non sono d'accordo. Struct e classi con generici hanno lo stesso problema. Altri linguaggi (C#, java, solo per citarne alcuni) consentono protocolli con generici.E comunque una serie di 'MyProtocol' ** ha ** la stessa funzionalità - ciò che è diverso è che ogni elemento può avere la funzionalità implementata in un modo diverso - ma lo stesso concetto si applica all'utilizzo di una classe base come tipo di elemento array e mettere le istanze degli oggetti ereditati da esso. – Antonio

+0

@Antonio Grazie, per come la vedo, il casting è probabilmente l'unica soluzione qui. Nel mio precedente tentativo stavo effettivamente utilizzando un parametro generico di classe uno, ma Swift non consente (ancora) di avere un tipo non generico che erediti da uno generico - 'XYZ: ABC ' non è permesso. – erudel

Problemi correlati