【问题标题】:Swift 2 value extraction from Enum从枚举中提取 Swift 2 值
【发布时间】:2015-10-03 00:48:35
【问题描述】:

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

有意义吗?

【问题讨论】:

  • 你为什么要声明自己的Maybe 类型呢?这正是Optionals 的用途!
  • 其实不是。它不符合NilLiteralConvertable。如果您想明确说明某个值的缺失或提供有关缺失原因的更多信息,则可以使用类似的方法。
  • 你想用什么语法来处理这个Either?也许您想给出您要解决的实际示例(因为Either 也得到了很好的探索:github.com/robrix/Either)。基本上:你想编译什么今天没有编译?

标签: swift enums


【解决方案1】:

你想要的语法在今天的 Swift 中是不可能的(明天的 Swift 感觉不太可能,但我经常感到惊讶)。最好的解决方案是提取函数,如left() -&gt; L? 和right() -&gt; 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")
}

【讨论】:

  • 这在功能上等同于创建一个value 变量,它实际上并没有解决我面临的问题......它只是将它移动到一个中缀运算符。此外,如果我有多个具有不同值的 case 语句,这并没有太大帮助。我会更新我的问题,使其更具体。
  • 好的;您的问题似乎表明这是您反对的 value() 函数。我会对您的实际问题感兴趣。
  • 好的,我尝试使用实际的语法示例进行更新。显然,这种语法不起作用,但它给出了我想要完成的任务的想法。
  • 是的,我认为这可能是不可能的,但它会很好。我查看了 Rob 的 Either,它几乎与我自己的实现完全一样(我没有粘贴整个内容)。我希望我可以使用某种功能范式来解决问题,但我还没有得到任何东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-10
  • 2013-04-07
  • 1970-01-01
  • 2016-07-11
  • 2020-09-23
  • 1970-01-01
  • 2012-12-28
相关资源
最近更新 更多