2016-04-24 2 views
6

У меня есть протокол моей быстрой базы кода У меня есть протокол со связанным типом и двумя методами. Оба метода определяют разные общие ограничения для связанного типа протокола. И я хотел бы, чтобы структура соответствовала двум протоколам, но с двумя разными связанными типами.реализовать протокол с другим связанным типом

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 
} 

В качестве расширения я делаю структура соответствует протоколу, где TargetType будет String для того, чтобы передать его в метод показа:

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

До сих пор все работает, как ожидалось. Но теперь мне также нравится, чтобы структура соответствовала протоколу Convertable, когда TargetType привязан к Int. Что кажется невозможным?

Первое, что я попытался было добавить второе определение метода новообращенного к расширению:

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

Теперь компилятор жалуется, что MyData уже больше не соответствует протоколу. Во-вторых, нужно разбить это на два расширения и явно привязать TargetType.

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

Это приводит к тому, что компилятор в настоящее время жалуется TargetType была пересмотрена.

Моя последняя попытка была определить два протокола, которые расширяют протокол Convertable и ограничить TargetType, а затем реализовать их обоих с помощью расширения:

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) } 
} 

который теперь делает компилятор счастливым для расширения, но уже не для вызов show, потому что он не знает, что он может вызывать функцию с MyData.

Есть ли что-то, что я наблюдал или это в настоящее время невозможно в быстром?

+1

Это не только в настоящее время невозможно, но, по моему мнению, вряд ли это будет возможно. Вы объявили протокол с одним единственным ассоциированным типом. Как он может быть установлен на два разных типа в одном и том же типе ?! – werediver

+1

Ну, это не тот же протокол, так как протокол является общим для TargetType, существует так много вариантов протокола, как для TargetType. Вся идея наличия типов, связанных с протоколами, заключается в том, что вы можете различать их связанный тип. Если вы посмотрите на C#, там можно реализовать тот же интерфейс с разными типами, связанными с общим параметром. – Kolja

+0

Ну, это не C#, и вы не должны думать об этом так, как было бы, потому что это просто не работает. – werediver

ответ

1

Я просто финансирую способ архивирования этого. Хитрость заключается в том, чтобы добавить еще один связанный с ним тип в одном из подтипов протокола:

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 } 
} 

Это также позволяет избавиться от второго подтипа для строки.

Пока это передает компилятор, он полностью сбой во время выполнения!

Компилятор всегда вызывает определенный метод, определенный в явном typealias. В этом случае:

typealias TargetType = String 

что приведет к интерпретации адреса как целое и дать вам совершенно неправильные результаты. Если вы определите его наоборот, он просто сработает, потому что он пытается интерпретировать целое число как адрес.

Смежные вопросы