在Swift 2之前,我经常使用带有关联值的枚举,并添加函数来提取特定值,如下所示:
public enum Maybe <T> {
case Unknown
case Known(T)
public var value: T? {
switch self {
case .Unknown: return nil
case .Known(let value): return value
}
}
}
这可以让我做这样的事情:
let maybe = .Known("Value")
let val = maybe.value ?? "Another Value"
我想摆脱这些便利功能,并依赖Swift 2的新语法。这可能是这样的:
let val: String
if case .Known(let value) = maybe {
val = value
} else {
val = "Another Value"
}
但我无法弄清楚如何使用??
运算符甚至三元运算符将其压缩成一行。
这甚至可能还是我坚持在枚举上定义“提取”选项?
Maybe
枚举只是一个示例,但解决方案需要处理具有多个关联值的枚举......例如Either
:
public enum Either<L, R> {
case Left(Box<L>)
case Right(Box<R>)
public func left() -> L?{
switch self {
case let Left(value):
return value.value
default:
return nil
}
}
public func right() -> R?{
switch self {
case let Right(value):
return value.value
default:
return nil
}
}
}
我正在寻找的语法类似于:
let val = (case .Known(let value) = maybe) ?? "AnotherValue"
我想要做的是轻松提取特定案例的关联值,否则提供默认值。
对于Either
,它可能类似于:
let val = (case .Left(let value) = either) ?? "AnotherValue"
有意义吗?
答案 0 :(得分:3)
你想要的语法在今天的Swift中是不可能的(并且明天对Swift感觉不太可能,但我常常感到惊讶)。最好的解决方案是提取功能,如left() -> L?
和right() -> R?
。 case
不是可以扩展的通用值返回函数。请参阅Rob Rix的Either
,了解当前对此问题的最佳看法。
Swift的一个关键选择是有许多语句不是表达式。 switch
就是其中之一。在Swift使switch
和if
之类的东西成为表达式之前,构建这种语法IMO将非常困难。
只需为其定义??
:
func ??<T>(lhs: Maybe<T>, @autoclosure defaultValue: () throws -> T) rethrows -> T {
switch lhs {
case .Unknown: return try defaultValue()
case .Known(let value): return value
}
}
let maybe = Maybe.Known("Value")
let val = maybe ?? "Another Value"
这样做可以在Swift2中为我们提供一些不错的功能。例如,我们可以懒惰地评估rhs,我们可以处理投掷rhs:
func computeIt() -> String {
print("LAZY!")
return "Computed"
}
maybe ?? computeIt() // Does not print "LAZY!"
Maybe.Unknown ?? computeIt() // Does print "LAZY!"
enum Error: ErrorType {
case Failure
}
func fail() throws -> String {
throw Error.Failure
}
try maybe ?? fail() // Doesn't throw
do {
try Maybe.Unknown ?? fail() // throws
} catch {
print("THROW")
}