2016-04-24 11 views
6

Mam protokół, mój kod szybkiego połączenia Mam protokół z powiązanym typem i dwie metody. Obie metody definiują różne ogólne ograniczenia dla skojarzonego typu protokołu. I chciałbym, aby struct był zgodny z protokołem, ale z dwoma różnymi powiązanymi typami.implementuj protokół z innym powiązanym typem:

protocol Convertable { 
    associatedtype TargetType 
    func convert() -> TargetType 
} 

func show<T : Convertable where T.TargetType == String>(toShow : T) { 
    print(toShow.convert()) 
} 
func add<T : Convertable where T.TargetType == Int>(a : T, b : T) -> Int { 
    return a.convert() + b.convert() 
} 

struct MyData { 
    var data : Int 
} 

Jako rozszerzenie robię struct zgodne z protokołem gdzie TargetType będzie String, aby przekazać je do metody pokazu:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
} 

Jak dotąd wszystko działa zgodnie z oczekiwaniami. Ale teraz lubię mieć strukturę zgodną z protokołem Convertable, gdy TargetType jest związany z Int. Co wydaje się niemożliwe?

Pierwszą rzeczą próbowałem było dodać drugą definicję metody konwersji do rozszerzenia:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
    func convert() -> Int { return data } 
} 

Kompilator teraz narzeka, że ​​nie ma już MyData zgodne z protokołem. Drugim było podzielenie tego na dwa rozszerzenia i bezpośrednie powiązanie TargetType.

extension MyData : Convertable { 
    typealias TargetType = Int 
    func convert() -> Int { return data } 
} 
extension MyData : Convertable { 
    typealias TargetType = String 
    func convert() -> String { return String(data) } 
} 

Ma to ten skutek, że kompilator teraz narzeka The TargetType został na nowo.

Moja ostatnia próba była definiować dwa protokoły, które rozciągają się protokół Convertable i ograniczyć TargetType a następnie wdrożyć oboje poprzez rozszerzenie:

protocol ConvertableString : Convertable { 
    associatedtype TargetType = String 
} 
protocol ConvertableInt : Convertable { 
    associatedtype TargetType = Int 
} 

extension MyData : ConvertableInt { 
    func convert() -> Int { return self.data } 
} 
extension MyData : ConvertableString { 
    func convert() -> String { return String(self.data) } 
} 

Co teraz robi kompilator szczęśliwy dla rozszerzeń, ale nie dłużej wywołanie show, ponieważ nie wie, że może wywołać funkcję z MyData.

Czy jest coś, co nadzorowałem, czy nie jest to obecnie możliwe w szybkim tempie?

+1

Nie tylko obecnie nie jest to możliwe, ale moim zdaniem nie będzie to możliwe. Deklarowałeś protokół z _jednym typem powiązanym. Jak można ustawić dwa różne typy tego samego typu ?! – werediver

+1

Cóż, to nie jest ten sam protokół, ponieważ protokół jest ogólny w stosunku do TargetType, istnieje tyle wariantów protokołu, co w przypadku TargetType. Cała idea posiadania typów powiązanych z protokołami polega na tym, że można je rozróżnić według skojarzonego typu. Jeśli spojrzysz na C#, istnieje możliwość zaimplementowania tego samego interfejsu z różnymi typami powiązanymi z ogólnym parametrem. – Kolja

+0

Cóż, to nie jest C# i nie powinieneś myśleć o tym tak, jak by to było, ponieważ to po prostu nie działa. – werediver

Odpowiedz

1

Po prostu sfinansuję sposób na zarchiwizowanie tego. Sztuką jest, aby dodać kolejną związaną typu w jednym z podtypów protokołu:

protocol ConvertableInt : Convertable { 
    associatedtype TResI 
    typealias TargetType = TResI 
} 

extension MyData : Convertable { 
    typealias TargetType = String 
    func convert() -> String { return String(self.data) } 
} 

extension MyData : ConvertableInt { 
    typealias TResI = Int 
    func convert() -> TResI { return self.data } 
} 

Pozwala także pozbyć się drugiego podtypu na sznurku.

Podczas przechodzenia przez kompilator całkowicie ulega awarii w czasie wykonywania!

Kompilator zawsze wywołuje zdefiniowaną metodę, która została zdefiniowana w jawnym typealias. W takim przypadku:

typealias TargetType = String 

Co spowoduje interpretację adresu jako liczby całkowitej i da całkowicie błędne wyniki. Jeśli zdefiniujesz to na odwrót, spowoduje to awarię, ponieważ próbuje zinterpretować liczbę całkowitą jako adres.

Powiązane problemy