swift - 在 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
子句扩展协议并提供必要的胶水以满足编译器的要求,即该协议的要求由所讨论的类型满足。
这仅适用于协议扩展中的函数体/属性访问器具有仅适用于协议扩展(但不适用于结构/类的扩展)的特殊能力。
协议扩展的这种特殊能力是扩展中的实现可以访问结构/类的相同变量或函数的原始实现,这些变量或函数在符合被扩展协议并满足where
子句要求的任何类型中声明。
由于协议扩展的这种特殊能力,以下不是无限循环:
extension Foo where Self == Bar.Bar {
var id: Id { self.id }
}
推荐阅读
- api - Ionic3 API 身份验证
- bash - 用于查找父 GOPATH 的 Bash 命令
- amazon-web-services - aws-sdk : DynamoDB : 获取所有表的列表
- css - 在 R Shiny 中更改 navbarPage 菜单栏的悬停字体颜色
- javascript - 当我尝试设置一个 HTML 和 JS
- sql-server - SQL Server 存在返回类型
- java - 设置真值列表
- mysql - 加入另一个表时,如何在 MYSQL 中使用稍后添加的列作为查询
- libgdx - Libgdx:我可以通过读取文本文件在屏幕上绘制文本吗?
- r - R 根据不同长度的其他列表制作列表