2014-07-12 12 views
25

che sto cercando di fare quanto segue in Swift:Perché questo protocollo "può essere utilizzato solo come un vincolo generico"?

protocol ProtocolWithAlias { 
    typealias T 
} 

protocol AnotherProtocol { 
    func someFunc() -> ProtocolWithAlias 
} 

ma ho l'errore: Protocol 'ProtocolWithAlias' can only be used as a generic constraint because it has Self or associated type requirements.

È possibile fare qualcosa di simile? Il messaggio di errore (o almeno la parte "only be used as a generic constraint") non sembra avere molto senso per me.

che sto utilizzando la più recente Xcode 6 beta 3.

Grazie!

risposta

23

Prova questo:

func someFunc<T:ProtocolWithAlias>() -> T 
+0

sarebbe vi capita di sapere perché è fatto in quel modo? Sembra una sintassi piuttosto strana, ma forse è solo perché sono abituato a C# :) – MatthewSot

+7

Il problema è che il sistema di tipi non sa cosa collegare per il tipo associato se si specifica solo il protocollo, quindi invece si crea una funzione generica che può essere specializzata per restituire qualsiasi tipo concreto specifico conforme al protocollo, ma non solo "il protocollo". Il compilatore dovrebbe probabilmente essere in grado di capirlo, ma non può al momento. –

+2

bello ma come specificare questo protocollo generico per una variabile di istanza di una classe? – Dragouf

10

E 'possibile implementare questa invertendo il controllo: invece di restituire un valore da somefunc passiamo un consumatore in grado di accettare qualsiasi tipo di implementazione ProtocolWithAlias ​​ e fare qualcosa con esso.

protocol ProtocolWithAlias { 
    typealias T 
} 

protocol ProtocolConsumer { 
    func consume<T: ProtocolWithAlias>(value: T) 
} 

protocol AnotherProtocol { 
    func someFunc(consumer: ProtocolConsumer) 
} 

Questo trucco è noto come trasformare la funzione in continuation passing style (CPS). Purtroppo non sono riuscito a trovare alcun modo per implementare questo senza CPSing. La funzionalità di sistema di tipi che stiamo cercando è di tipo esistenziale (e il thread this ha una bella spiegazione), ma penso che Swift non li supporti (ancora).


Perché l'altra risposta non è corretta? Che cosa questa firma dice:

func someFunc<T:ProtocolWithAlias>() -> T 

è che questa funzione può restituire un valore di tipo T per qualsiasi tipo attuazione ProtocolWithAlias ​​ che le chiamante sceglie, ma abbiamo voluto che essere scelto dal callee.

Non è nemmeno possibile scrivere un'implementazione ragionevole di questa funzione. Consente di far finta Ho un'implementazione di somefunc: ho potuto creare una nuova classe che implementa ProtocolWithAlias ​​ e richiedere somefunc di creare in qualche modo un esempio di questa classe:

class Uninhabited: ProtocolWithAlias { 
    typealias T = Int 
    init(nope: Uninhabited) {} 
} 

... 

let impossible: Uninhabited = someFunc<Uninhabited>() 
Problemi correlati