我想扩展Array以增加对新协议的一致性-但仅适用于其元素本身符合特定协议的数组。
Array
更笼统地说,我想让带有类型参数的类型(无论是协议类型还是具体类型)仅在类型参数与某些约束匹配时才实现协议。
从Swift 2.0开始,这似乎是不可能的。有什么我想念的方式吗?
假设我们有以下Friendly协议:
Friendly
protocol Friendly { func sayHi() }
我们可以扩展现有的类型来实现它:
extension String: Friendly { func sayHi() { print("Greetings from \(self)!") } } "Sally".sayHi()
我们还可以扩展Array实现sayHi()其所有元素时的实现Friendly:
sayHi()
extension Array where Element: Friendly { func sayHi() { for elem in self { elem.sayHi() } } } ["Sally", "Fred"].sayHi()
在这一点上,类型[Friendly]本身应该实现Friendly,因为它符合协议的要求。 但是,此代码无法编译 :
[Friendly]
extension Array: Friendly where Element: Friendly { func sayHi() { for elem in self { elem.sayHi() } } }
错误消息是“具有约束的’Array’类型的扩展不能具有继承子句”,这似乎最终确定了直接方法的大门。
有间接解决方法吗? 我可以使用一些巧妙的技巧?也许有一种方法涉及扩展SequenceType而不是Array?
SequenceType
一个可行的解决方案将使此代码编译:
let friendly: Friendly = ["Foo", "Bar"]
更新: 它已落入Swift 4.1中,真是太美了!
extension Array: Friendly where Element: Friendly现在,该示例将按照原始问题中的说明进行编译。
extension Array: Friendly where Element: Friendly
编辑:如更新的问题中所述,自Swift 4.1起,现在可以实现
目前在Swift中(从Xcode 7.1开始)无法实现。如错误所示,您不能将协议一致性(“继承子句”)限制为类型受限的扩展。也许有一天。我不认为没有任何可能的深层原因,但是目前尚未实现。
您可以获得的最接近的结果是创建一个包装器类型,例如:
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。)
FriendlyArray
CollectionType
有关我自己陷入尝试进行这项工作的疯狂以及我从边缘爬回的故事,请参阅NSData,我的老朋友。