Условное соответствие протокола протоколу - PullRequest
0 голосов
/ 03 июня 2019

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

Давайте рассмотрим пример: я определяю протокол ShowableAsInt, который позволяет получить представление Int для любого типа, который ему соответствует.

protocol ShowableAsInt {
        func intRepr() -> Int
}

extension Int : ShowableAsInt {
    func intRepr() -> Int {
        return self
    }
}

extension String : ShowableAsInt {
    func intRepr() -> Int {
        return self.count
    }
}

func show(_ s: ShowableAsInt) {
    print(s.intRepr())
}

show("abc") // "3"
show(42) // "42"

Теперь я определяю *Протокол 1008 *, который просто оборачивает элемент.

protocol Container {
    associatedtype T
    var element: T {
        get
    }
}

struct StringContainer : Container {
    typealias T = String
    let element: String
}

struct IntContainer : Container {
    typealias T = Int
    let element: Int
}

Поскольку Container - простая обертка, всякий раз, когда обернутый тип может быть показан как Int, контейнер также может быть показан как Int.Я пытался выразить это, но не смог:

// Doesn't compile: can't extend a protocol to conform to another one?
extension Container : ShowableAsInt where T : ShowableAsInt {
    func intRepr() -> Int {
        return element.intRepr()
    }
}

// I would like these to compile
show(IntContainer(42)) // "42"
show(StringContainer("abc")) // "3"

Я знаю, что это условное соответствие может быть выражено на class и struct.Есть ли способ сделать то же самое для протоколов?Если нет, есть ли причина для такого ограничения?

1 Ответ

2 голосов
/ 03 июня 2019

Причина, по которой это запрещено, указывается здесь :

Это расширение протокола сделало бы любую Коллекцию Equatable элементов Equatable, что является мощной функцией, которую можно было бы эффективно использовать. Введение условных соответствий для расширений протокола усугубит проблему перекрывающихся соответствий, , поскольку было бы неразумно утверждать, что существование вышеуказанного расширения протокола означает, что ни один тип, который соответствует Collection, не может объявить свое собственное соответствие Equatable, условно или иным образом.

См. Также этот вопрос .

Если вы просто не хотите каждый раз писать дублирующую реализацию intRepr, вы можете сделать это:

struct StringContainer : ShowableAsIntContainer {
    typealias T = String
    let element: String
}

struct IntContainer : ShowableAsIntContainer {
    typealias T = Int
    let element: Int
}

extension Container where T : ShowableAsInt {
    func intRepr() -> Int {
        return element.intRepr()
    }
}

typealias ShowableAsIntContainer = ShowableAsInt & Container
...