在Swift中遵循具有相同变量名的协议时如何避免无限循环?
How to avoid infinite loop when conforming to a protocol with the same variable name in Swift?
给定 FooModule 中的以下协议:
protocol Id {
var id: String { get }
}
protocol Foo {
var id: Id { get }
}
...以及来自 ThirdPartyModule 的一些不符合它的类型,但已经有一个 属性 id
:
struct 3rdPartyId {
var id: String
}
struct 3rdPartyElement {
var id: 3rdPartyId
}
现在我想做:
extension 3rdPartyId: MyModule.Id {
var id: String { return self.id }
}
extension 3rdPartyElement: MyModule.Element {
var id: MyModule.Id { return self.id }
}
然而,这会导致无限循环。
如何扩展 3rdPartyElement 以符合 MyModule.Element 协议而不会出现无限循环...?
我也试过这样声明:
extension 3rdPartyElement: MyModule.Element {}
... 因为已经有一个 属性 id
的类型应该满足协议。然而,这也不起作用,我收到一个编译器错误,告诉我添加 属性 getter,这当然会形成一个循环。
这是我想出的:
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
子句扩展协议和提供必要的胶水来满足编译器协议的要求被所讨论的类型所满足。
这之所以有效,是因为协议扩展中的函数体/属性 访问器具有一种特殊的能力,这种能力仅适用于协议扩展(但不适用于 structs/classes 上的扩展)。
协议扩展的这种特殊能力是扩展中的实现可以访问声明的相同变量或函数的结构's/class的原始实现在符合正在扩展的协议并满足 where
子句要求的任何类型中。
由于协议扩展的这种特殊能力,以下不是无限循环:
extension Foo where Self == Bar.Bar {
var id: Id { self.id }
}
给定 FooModule 中的以下协议:
protocol Id {
var id: String { get }
}
protocol Foo {
var id: Id { get }
}
...以及来自 ThirdPartyModule 的一些不符合它的类型,但已经有一个 属性 id
:
struct 3rdPartyId {
var id: String
}
struct 3rdPartyElement {
var id: 3rdPartyId
}
现在我想做:
extension 3rdPartyId: MyModule.Id {
var id: String { return self.id }
}
extension 3rdPartyElement: MyModule.Element {
var id: MyModule.Id { return self.id }
}
然而,这会导致无限循环。
如何扩展 3rdPartyElement 以符合 MyModule.Element 协议而不会出现无限循环...?
我也试过这样声明:
extension 3rdPartyElement: MyModule.Element {}
... 因为已经有一个 属性 id
的类型应该满足协议。然而,这也不起作用,我收到一个编译器错误,告诉我添加 属性 getter,这当然会形成一个循环。
这是我想出的:
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
子句扩展协议和提供必要的胶水来满足编译器协议的要求被所讨论的类型所满足。
这之所以有效,是因为协议扩展中的函数体/属性 访问器具有一种特殊的能力,这种能力仅适用于协议扩展(但不适用于 structs/classes 上的扩展)。
协议扩展的这种特殊能力是扩展中的实现可以访问声明的相同变量或函数的结构's/class的原始实现在符合正在扩展的协议并满足 where
子句要求的任何类型中。
由于协议扩展的这种特殊能力,以下不是无限循环:
extension Foo where Self == Bar.Bar {
var id: Id { self.id }
}