我想扩展Array
以添加对新协议(protocol)的一致性 - 但仅限于元素本身符合特定协议(protocol)的数组。
更一般地说,我希望具有类型参数的类型(无论是协议(protocol)还是具体类型)仅当类型参数匹配某些约束时才实现协议(protocol)。
从 Swift 2.0 开始,这似乎是不可能的。有什么办法是我想念的吗?
示例
假设我们有Friendly
协议(protocol):
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
,因为它满足协议(protocol)的要求。 但是,此代码无法编译:
extension Array: Friendly where Element: Friendly {
func sayHi() {
for elem in self {
elem.sayHi()
}
}
}
错误消息是“带有约束的‘Array’类型的扩展不能有继承子句”,这似乎彻底关闭了这种直接方法的大门。
有间接的解决方法吗?我可以使用一些聪明的技巧吗?也许有一种方法涉及扩展 SequenceType
而不是 Array
?
一个可行的解决方案将使此代码编译:
let friendly: Friendly = ["Foo", "Bar"]
<小时/>
更新:这已经在 Swift 4.1 中实现,它是一件美丽的事情!
扩展数组:友好,其中元素:友好
示例现在按照原始问题中给出的方式进行编译。
最佳答案
编辑:正如更新的问题中所述,自 Swift 4.1 以来现在可以实现这一点
<小时/>目前这在 Swift 中是不可能的(从 Xcode 7.1 开始)。正如错误所示,您不能将协议(protocol)一致性(“继承子句”)限制为类型约束的扩展。也许有一天。我不认为有任何深层原因导致这是不可能的,但目前尚未实现。
您可以获得的最接近的是创建一个包装类型,例如:
struct FriendlyArray<Element: Friendly>: Friendly {
let array: [Element]
init(_ array: [Element]) {
self.array = array
}
func sayHi() {
for elem in array {
elem.sayHi()
}
}
}
let friendly: Friendly = FriendlyArray(["Foo", "Bar"])
(您可能希望将 FriendlyArray
扩展为 CollectionType
。)
有关我自己陷入疯狂并试图让这项工作成功以及我从边缘爬回来的故事,请参阅 NSData, My Old Friend .
关于swift - 是否可以向 Swift 协议(protocol)一致性扩展添加类型约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34861236/