从Enum中提取Swift 2值

时间:2015-10-02 16:18:31

标签: swift enums

在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"

有意义吗?

1 个答案:

答案 0 :(得分:3)

你想要的语法在今天的Swift中是不可能的(并且明天对Swift感觉不太可能,但我常常感到惊讶)。最好的解决方案是提取功能,如left() -> L?right() -> R?case不是可以扩展的通用值返回函数。请参阅Rob Rix的Either,了解当前对此问题的最佳看法。

Swift的一个关键选择是有许多语句不是表达式。 switch就是其中之一。在Swift使switchif之类的东西成为表达式之前,构建这种语法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")
}