你希望Swift能做一些它不能做的事情。就我所知,Swift没有union类型。如果你需要类似的功能,可能需要查看函数式或函数式启发的语言。
< p > < em >插曲: 如果两种类型都是结构体或类(即不是协议),则可以使用此模式:
protocol DataOrError {}
extension Data: DataOrError {}
extension ErrorClass: DataOrError {}
假设没有其他协议实现者,那么你现在拥有了接近联合类型的东西。你也可以对类型进行switch-case操作:
switch doe {
case let e as Error: print("Error \(e)")
case let d as Data: print("Data \(d)")
default: assert(false, "thou shalt not implement my dummy!")
}
无论如何,我们可以使用带有关联值的枚举来模拟联合类型(在某些限制下)。这可以作为一种低配版的联合类型。
像这样定义一个枚举:
enum DataOrError {
case Data(Data)
case Error(Error)
}
现在你可以在任何需要(确切地)有一个
Data
或
Error
的地方使用
DataOrError
,并且对于最多一个,可以使用
DataOrError?
。
在调用站点,您会得到类似于这样的东西:
extension String: Error {}
func myFunction(completion: (DataOrError) -> ()) {
completion(.Data(Data(bytes: [1,2,3,4,5])))
completion(.Error("this won't work!"))
}
And callee-site:
var myCompletion = { (doe: DataOrError) in
switch doe {
case .Data(let d): print("Data \(d)")
case .Error(let e): print("Error \(e)")
}
}
myFunction(completion: myCompletion)
设计说明:如果您有多种类型要与Error
进行OR运算,您可能正在寻找另一种方向的泛化。在这种情况下,即使您牺牲了良好的语法,明确的包装器也可能是一个好的解决方案。
struct TalkativeOptional<T> {
private(set) var rawValue: T?
private(set) var error: Error?
init(value: T) {
self.rawValue = value
}
init(error: Error) {
self.error = error
}
}
请注意这两个属性中只有一个可以是非
nil
的。还有两种组合方式;您可以通过选择初始化程序来控制您想要的组合方式。
调用示例:
func convert(_ number: String) -> TalkativeOptional<Int> {
if let int = Int(number) {
return TalkativeOptional(value: int)
} else {
return TalkativeOptional(error: "'\(number)' not a valid integer!")
}
}
示例调用站点:
var a = convert("dsa2e2")
if let val = a.rawValue {
print("a + 1 = \(val + 1)")
} else {
print("ERROR: \(a.error!)")
}