为什么这个开关在不详尽的情况下编译?

时间:2018-02-14 20:32:25

标签: swift switch-statement

我有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,所以交换机中的任何情况都不匹配。我认为这意味着从该方法返回垃圾。

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

修改

通过添加这样的最终案例在操场上修好:

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

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

1 个答案:

答案 0 :(得分:0)

我假设您在定义Foundation类型的文件中导入Result。好吧,这有一些(有时)不需要的编译器将Swift值桥接到Objective-C兼容对象的效果,这就是你的情况。

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