【问题标题】:Why does this switch compile when it's not exhaustive?为什么这个开关在不详尽时会编译?
【发布时间】:2018-07-25 12:42:19
【问题描述】:

我有这个Result 枚举:

public enum Result<T> {
    case success(T)
    case failure(Error)
}

并且想实现CustomStringConvertible,所以我做到了。 (不要戳破这个问题,这个问题已经简化了:):

extension Result: CustomStringConvertible {

    public var description: String {
        switch self {
        case .success(let value as CustomStringConvertible):
            return "Result.success(\(value.description))"
        case .success(let value):
            return "Result.success(\(value))"
        case .failure(let error as CustomStringConvertible):
            return "Result.failure(\(error.description))"
        }
    }
}

在 Playground 中运行它完全符合要求。但是,它在最终的r.description 上出错。 (同样的运行时故障发生在我的应用程序中,因此与在操场上无关。)

var r: Result<String> = .success("hello")
r.description

r = .failure(NSError(domain: "", code: 0, userInfo: nil))
r.description

struct MyError: Error { }
r = .failure(MyError())
r.description

经过大量的挠头和代码设置后,我发现这是因为MyError 没有实现CustomStringConvertible,所以在switch 中没有case 匹配。我认为这意味着垃圾是从该方法返回的。

那么,有谁知道为什么这个开关会编译?


编辑

在操场上通过添加这样的最终案例来解决此问题后:

case .failure(let error):
    return "Result.failure(\(error))"

它有效。但是,当我将它添加回我的应用程序时,编译器大胆地发出警告:warning: case is already handled by previous patterns; consider removing it - 这是 Swift 中的错误(不太可能)还是我误解了 ErrorCustomStringconvertible 之间的关系(更有可能)?

【问题讨论】:

  • 将第三种情况定义为case .failure(let error as NSError): 使其适用于所有情况(并且没有警告),但我没有完整的解释。
  • 编译器似乎认为Error总是采用CustomStringConvertible,但只有在桥接到NSError时才会这样做。
  • 好吧,这就是我的假设,但只是想确保我没有完全发疯!
  • case .failure(let error): return "Result.failure(\((error as CustomStringConvertible).description))" 也可以...
  • 我在这里提出了一个错误:bugs.swift.org/browse/SR-7001 看看他们是怎么做的。

标签: swift switch-statement


【解决方案1】:

我假设您在定义Result 类型的文件中导入Foundation。好吧,这有(有时)编译器将 Swift 值桥接到 Objective-C 兼容对象的不良影响,这就是在您的情况下发生的情况。

删除import Foundation 子句将导致您的开关由于不详尽而不再编译。我怀疑Foundation 导入将CustomStringConvertible 协议从.failure 案例桥接到一些Objective-C 值,但不正确,这会导致应用程序崩溃。

【讨论】:

  • 我已经从我的文件中删除了import Foundation,但我仍然遇到同样的错误。这是 Xcode 为我添加的东西吗 - 你是在 Xcode 中工作还是在做命令行的事情(我对 Foundation 等如何导入了解不够)
  • @deanWombourne 可能是 Foundation 导入来自在 Result 之前编译的文件。您可以尝试将该文件移动到专用库中,看看是否能解决问题。或者,您可以添加第 4 个枚举案例 :)
  • 我已经花了 4 个小时没有找到这个,所以我提出了一个错误并编写了第 4 个案例。现实和最后期限正在密谋反对我! (错误在这里:bugs.swift.org/browse/SR-7001
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
相关资源
最近更新 更多