2014-07-12 11 views
25

Ja próbuje wykonać następujące czynności w Swift:Dlaczego ten protokół "może być używany tylko jako ogólne ograniczenie"?

protocol ProtocolWithAlias { 
    typealias T 
} 

protocol AnotherProtocol { 
    func someFunc() -> ProtocolWithAlias 
} 

Ale pojawia się błąd: Protocol 'ProtocolWithAlias' can only be used as a generic constraint because it has Self or associated type requirements.

Czy można zrobić coś takiego? Komunikat o błędzie (lub przynajmniej część "only be used as a generic constraint") nie ma dla mnie większego sensu.

Używam najnowszego Xcode 6 beta 3.

Dzięki!

Odpowiedz

23

Spróbuj tego:

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

będzie pan wie, dlaczego to zrobić w taki sposób? Wydaje się, że jest to raczej dziwna składnia, ale może dlatego, że jestem przyzwyczajony do C# :) – MatthewSot

+7

Problem polega na tym, że system typów nie wie, co podłączyć w powiązanym typie, jeśli tylko określisz protokół, więc zamiast tego tworzysz funkcję ogólną, która może być wyspecjalizowana w zwracaniu konkretnego konkretnego typu betonu zgodnego z protokołem, ale nie tylko "protokołem". Kompilator powinien prawdopodobnie być w stanie to zrozumieć, ale nie może obecnie. –

+2

ładne, ale jak określić ten ogólny protokół do zmiennej instancji klasy? – Dragouf

10

Jest to możliwe do wykonania tego przez odwracanie kontrolę: zamiast zwracania wartości z someFunc mijamy konsumenta, który może przyjąć każdy rodzaj wykonania ProtocolWithAlias ​​ i zrobić coś z to. To jest znana jako przekształcenie funkcji na continuation passing style (CPS). Niestety nie mogłem znaleźć żadnego sposobu na wdrożenie tego bez CPSing. Typ systemu, którego szukamy, to typy egzystencjalne (i wątek this ma ładne wyjaśnienie), ale myślę, że Swift ich nie obsługuje (jeszcze).


Dlaczego druga odpowiedź jest nieprawidłowa? Co mówi ten podpis:

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

jest to, że ta funkcja może zwracać wartość typu T dla każdego typu wykonawczego ProtocolWithAlias ​​ że rozmówcy Wybiera, ale chcieliśmy, żeby być wybrany przez callee.

Nie można nawet napisać sensownej implementacji tej funkcji. Pozwala udawać Mam realizację someFunc: można utworzyć nową klasę wykonawczą ProtocolWithAlias ​​ i poprosić someFunc jakoś utworzyć instancję tej klasy:

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

... 

let impossible: Uninhabited = someFunc<Uninhabited>() 
Powiązane problemy