【问题标题】:Swift add constraint extension to Protocol that has an associated typeSwift 向具有关联类型的协议添加约束扩展
【发布时间】:2021-12-16 01:31:15
【问题描述】:

当我向具有关联类型的协议添加约束扩展时,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 构建成功,它认为我的Doo 的Element 是String。它忽略了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

【问题讨论】:

  • 我认为这是因为约束是在很久以后才应用的(尽管我没有任何来源)。 Doo 得到了 node 方法“只要”你说 : Arr。然后它看到node 返回String?,所以它推断Element 必须是String。如果node 返回Element?,则无法进行推理。你知道 Swift 从方法签名中推断出关联的类型吗?
  • 只有在您尝试调用 node 时才会检查约束。只有这样编译器才会说“node 仅在...时可用”
  • The Xcode show an error for me expected - 您期望的错误是什么?
  • @Cristik Xcode 显示:Type 'Doo' does not conform to protocol 'Arr'

标签: swift protocols associated-types


【解决方案1】:

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

例如,假设扩展不存在,Doo 定义如下:

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

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

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

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

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

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

【讨论】:

  • 感谢您的回答。我理解你。编译器应用扩展中的函数然后检查约束,并全部实现。这说得通。但是这种行为很奇怪,我会尝试向 swift 项目报告错误。我认为编译器可能会首先检查扩展后的约束,如果它通过了,则将函数或变量添加到Doo struct。也许这可以减少意外添加的错误。因为在我的第一个代码 sn-p 中,Arr 协议有一个默认的Element 值是String。这是出乎意料的。很难找到那个原因。
  • 当然,如果您认为这是不正确的行为,您可以尝试提交错误报告,@sunny。基本上是编译器的急切导致了这种情况,有时过于乐于助人似乎不是最好的:)
【解决方案2】:

出现第二种情况的错误是因为 Xcode 无法推断 Element 的类型。如果你指定它,一切都会编译。

struct Doo: Arr {
    typealias Element = String
    
}

【讨论】:

  • 问题不在于为什么会发生错误,或者如何修复它。反过来说,为什么第一个代码sn-p没有错误。
  • 在第一种情况下,编译器能够推断出 Element 的类型,因为 func node 据说返回 String。
猜你喜欢
  • 1970-01-01
  • 2017-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
相关资源
最近更新 更多