Swift 向具有关联类型的协议添加约束扩展

Swift add constraint extension to Protocol that has an associated type

当我向具有关联类型的协议添加约束扩展时,swift 编译器会忽略我的约束。

当我写的时候:

protocol Arr {
    associatedtype Element

    func node(_ at: Int) -> Element?
}

extension Arr where Element == String {
    func node(_ at: Int) -> String? {
        nil
    }
}

struct Doo: Arr {
}

Xcode 构建成功,它认为我的 DooElementString。它忽略 where Element == String 约束。

当我写的时候:

protocol Arr {
    associatedtype Element

    func node(_ at: Int) -> Element?
}

extension Arr where Element == String {
    func node(_ at: Int) -> Element? { // use Element
        nil
    }
}

struct Doo: Arr {
}

Xcode 显示错误,正如预期的那样。

这是 Xcode 错误还是 Swift 功能?

Xcode版本:Version 13.1 (13A1030d)

Swift版本:

swift-driver version: 1.26.9 Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6)
Target: arm64-apple-macosx12.0

第二种情况的错误是因为Xcode无法推断出元素的类型。如果指定它,所有内容都会编译。

struct Doo: Arr {
    typealias Element = String
    
}

这里发生的是 Swift 如果可以从上下文中提取协议要求,它将很乐意满足协议要求。

例如,假设扩展名不存在,Doo 定义将是这样的:

struct Doo: Arr {
    func node(_ at: Int) -> String? {
        nil
    }
}

,Swift 编译器会愉快地填充 Element 关联类型。

您的第一段代码也会发生类似的情况,Doo 符合 Arr,并且编译器会找到一个满足所有协议要求的定义。 Swift 不会忽略 Element == String 约束,因为它将它与 Doo 结构相关联。

如果您以类似的方式添加第二个扩展,但对于另一种类型(例如 Int),您会看到收到预期的错误。发生这种情况是因为编译器无法再推断协议要求。

Swift 编译器急切地从它可以到达的上下文中推断出尽可能多的东西,大多数时候会给出很好的结果,有时不是很好(尤其是在使用闭包时),有时它会给出意想不到的结果(比如这个)。

如果您想确保编译器推断出您想要的类型,解决方案是显式声明所有涉及的类型。