【问题标题】:Is it possible to add type constraints to a Swift protocol conformance extension?是否可以向 Swift 协议一致性扩展添加类型约束?
【发布时间】:2015-10-25 17:19:47
【问题描述】:

我想扩展 Array 以增加对新协议的一致性 - 但仅限于其元素本身符合特定协议的数组。

更一般地说,我希望具有类型参数的类型(无论是协议还是具体类型)仅在类型参数匹配某些约束时才实现协议。

从 Swift 2.0 开始,这似乎是不可能的。有没有我想念的方法?

示例

假设我们有Friendly 协议:

protocol Friendly {
    func sayHi()
}

我们可以扩展现有类型来实现它:

extension String: Friendly {
    func sayHi() {
        print("Greetings from \(self)!")
    }
}

"Sally".sayHi()

sayHi()的元素都是Friendly时,我们也可以扩展Array来实现sayHi()

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 示例现在按照原始问题中给出的方式进行编译。

【问题讨论】:

标签: swift generics


【解决方案1】:

编辑:正如更新的问题中所述,这现在可以从 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。)

关于我自己陷入疯狂并试图完成这项工作的故事,以及我从边缘爬回来的故事,请参阅NSData, My Old Friend

【讨论】:

【解决方案2】:

好消息是您所要求的 Conditional Conformance 将在 Swift 4.1 中推出:

https://swift.org/blog/conditional-conformance/

【讨论】:

    猜你喜欢
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    相关资源
    最近更新 更多