【发布时间】: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 中的错误(不太可能)还是我误解了 Error 和 CustomStringconvertible 之间的关系(更有可能)?
【问题讨论】:
-
将第三种情况定义为
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 看看他们是怎么做的。