我想扩展 Array
以增加对新协议的一致性 - 但仅适用于其元素本身符合特定协议的数组 .
更一般地说,我希望类型参数的类型(无论是协议还是具体类型)仅在类型参数匹配某些约束时才实现协议 .
从Swift 2.0开始,这似乎是不可能的 . 有没有办法让我失踪?
示例
假设我们有 Friendly
协议:
protocol Friendly {
func sayHi()
}
我们可以扩展现有类型来实现它:
extension String: Friendly {
func sayHi() {
print("Greetings from \(self)!")
}
}
"Sally".sayHi()
我们也可以扩展 Array
来实现 sayHi()
,当它的元素都是 Friendly
时:
extension Array where Element: Friendly {
func sayHi() {
for elem in self {
elem.sayHi()
}
}
}
["Sally", "Fred"].sayHi()
此时,类型 [Friendly]
本身应该实现 Friendly
,因为它符合协议的要求 . 但是,此代码无法编译:
extension Array: Friendly where Element: Friendly {
func sayHi() {
for elem in self {
elem.sayHi()
}
}
}
错误消息是“带有约束的类型'数组'的扩展,不能有继承子句,”这似乎在这种直接方法上明确地关闭了大门 .
有间接的解决方法吗?我可以使用一些聪明的技巧?也许有一种方法涉及扩展SequenceType而不是Array?
一个有效的解决方案将使这段代码编译:
let friendly: Friendly = ["Foo", "Bar"]
Update: 这已经登陆Swift 4.1,这是一件美丽的事情!
extension Array: Friendly where Element: Friendly
示例现在编译为原始问题中给出的内容 .
2 回答
这在Swift中是不可能的(从Xcode 7.1开始) . 如错误所示,您不能将协议一致性(“继承子句”)限制为类型约束扩展 . 也许有一天 . 我不相信这是不可能的,但它目前尚未实施 .
您可以获得的最接近的是创建一个包装类型,例如:
(您可能希望将
FriendlyArray
扩展为CollectionType
. )对于我自己下降到试图使这项工作疯狂的故事,以及我从边缘爬回来的故事,请参阅NSData, My Old Friend .
好消息是你要求
Conditional Conformance
正在进入Swift 4.1:https://swift.org/blog/conditional-conformance/