Вот что я придумал:
public enum Bar {
@frozen
public struct Id {
private var _id: String = ""
public var id: String {
get { _id }
set { _id = newValue }
}
public init(id: String) {
_id = id
}
}
@frozen
public struct Bar {
public var id: Id
}
}
// MARK: - Protocols
protocol Id {
var id: String { get }
}
protocol Foo {
var id: Id { get }
}
// MARK: - Conformance
// (1) Declare that the type conforms to the protocol
// (won't compile without the second extension below)
extension Bar.Id: Id {}
// (2) Extend the protocol enough to ensure the compiler
// knows how the protocol conformance declared in (1)
// is supposed to actually work.
extension Id where Self == Bar.Id {
var id: String { self.id }
init(id: String) {
self.init(id: id)
}
}
// (1) Declare that the type conforms to the protocol
// (won't compile without the second extension below)
extension Bar.Bar: Foo {}
// (2) Extend the protocol enough to ensure the compiler
// knows how the protocol conformance declared in (1)
// is supposed to actually work.
extension Foo where Self == Bar.Bar {
var id: Id { self.id }
}
Ключ в том, что вам нужны два расширения: одно, которое объявляет, что тип соответствует протоколу, и другое, расширяющее протокол с предложением where
и обеспечивает необходимый клей, чтобы убедить компилятор, что требования протокола удовлетворяются рассматриваемым типом.
Это работает только потому, что тела функций / средства доступа к свойствам внутри расширений протокола имеют особая способность, которая характерна только для расширений протокола (но не для расширений структур / классов).
Эта особая способность расширений протокола заключается в том, что реализация в расширении может получить доступ к исходной реализации структуры / класса той же переменной или функции , объявленной внутри любого типа, который соответствует протоколу, расширяется и соответствует требованиям пункта where
.
Из-за этой особой способности расширений протокола следующее не является бесконечным l oop:
extension Foo where Self == Bar.Bar {
var id: Id { self.id }
}