是否可以向Swift协议一致性扩展中添加类型约束?

我想扩展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()

        }

    }

}

错误消息是“具有约束的'Array'类型的扩展不能具有继承子句”,这似乎最终确定了直接方法的大门。


有间接解决方法吗?我可以使用一些巧妙的技巧?也许有一种方法涉及扩展SequenceType而不是Array?


一个有效的解决方案将使此代码编译:


let friendly: Friendly = ["Foo", "Bar"]

更新:它已落入Swift 4.1中,真是太美了!


extension Array: Friendly where Element: Friendly现在,该示例将按照原始问题中的说明进行编译。


心有法竹
浏览 555回答 2
2回答

白猪掌柜的

编辑:如更新的问题中所述,自Swift 4.1起,现在可以实现目前在Swift中(从Xcode 7.1开始)无法实现。如错误所示,您不能将协议一致性(“继承子句”)限制为类型受限的扩展。也许有一天。我不认为没有任何可能的深层原因,但是目前尚未实现。您可以获得的最接近的结果是创建一个包装器类型,例如:struct FriendlyArray<Element: Friendly>: Friendly {&nbsp; &nbsp; let array: [Element]&nbsp; &nbsp; init(_ array: [Element]) {&nbsp; &nbsp; &nbsp; &nbsp; self.array = array&nbsp; &nbsp; }&nbsp; &nbsp; func sayHi() {&nbsp; &nbsp; &nbsp; &nbsp; for elem in array {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; elem.sayHi()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}let friendly: Friendly = FriendlyArray(["Foo", "Bar"])(您可能想扩展FriendlyArray为一个CollectionType。)有关我自己陷入尝试进行这项工作的疯狂以及我从边缘爬回的故事,请参阅NSData,我的老朋友。
打开App,查看更多内容
随时随地看视频慕课网APP