【问题标题】:Providing a default value for an Optional in Swift?为 Swift 中的 Optional 提供默认值?
【发布时间】:2014-07-28 19:05:31
【问题描述】:

在 Swift 中处理可选项的习语似乎过于冗长,如果您只想在它为 nil 的情况下提供一个默认值:

if let value = optionalValue {
    // do something with 'value'
} else {
    // do the same thing with your default value
}

这涉及不必要的重复代码,或

var unwrappedValue
if let value = optionalValue {
    unwrappedValue = value
} else {
    unwrappedValue = defaultValue
}

要求unwrappedValue 不是常数。

Scala 的 Option monad(与 Swift 的 Optional 基本相同)为此使用了 getOrElse 方法:

val myValue = optionalValue.getOrElse(defaultValue)

我错过了什么吗? Swift 是否已经有一种紧凑的方式来做到这一点?或者,如果做不到这一点,是否可以在 Optional 的扩展中定义 getOrElse?

【问题讨论】:

标签: swift optional


【解决方案1】:

更新

Apple 现在添加了一个合并运算符:

var unwrappedValue = optionalValue ?? defaultValue

在这种情况下,三元运算符是你的朋友

var unwrappedValue = optionalValue ? optionalValue! : defaultValue

您还可以为可选枚举提供自己的扩展:

extension Optional {
    func or(defaultValue: T) -> T {
        switch(self) {
            case .None:
                return defaultValue
            case .Some(let value):
                return value
        }
    }
}

那么你可以这样做:

optionalValue.or(defaultValue)

但是,我建议坚持使用三元运算符,因为其他开发人员无需研究 or 方法就能更快地理解这一点

注意:我创建了一个module,以便在Optional 上将or 之类的常用助手添加到swift。

【讨论】:

  • 我的编译器告诉我 unwrappedValue 的类型仍然是 Swift 1.2 中这种情况的可选类型:var unwrappedValue = optionalValue ? optionalValue! : defaultValue (xcode 6 beta 4)。这有变化吗?
  • 我的版本错了。我在6.4。请注意:?? 默认类型推断行为是它返回一个可选的,这通常不是您想要的。您可以将变量声明为非可选的,这很好用。
【解决方案2】:

截至 2014 年 8 月,Swift 具有允许这样做的合并运算符 (??)。例如,对于一个可选的 String myOptional 你可以这样写:

result = myOptional ?? "n/a"

【讨论】:

    【解决方案3】:

    如果你写了:

    let result = optionalValue ?? 50
    

    然后optionalValue != nil 然后result 也将是optional,您将来需要解开它

    但是你可以写操作符

    infix operator ??? { associativity left precedence 140 }
    
    func ???<T>(optLeft:T?, right:T!) -> T!
    {
        if let left = optLeft
        {
            return left
        }
        else { return right}
    }
    

    现在你可以:

     let result = optionalValue ??? 50
    

    当optionalValue != nil 那么result 将是unwraped

    【讨论】:

      【解决方案4】:

      以下似乎有效

      extension Optional {
          func getOrElse<T>(defaultValue: T) -> T {
              if let value = self? {
                  return value as T
              } else {
                  return defaultValue
              }
          }
      }
      

      然而,需要转换 value as T 是一个丑陋的黑客。理想情况下,应该有一种方法可以断言 T 与 Optional 中包含的类型相同。就目前而言,类型推断集T 基于给定给 getOrElse 的参数,然后在运行时失败,如果这与 Optional 不匹配并且 Optional 不为零:

      let x: Int?
      
      let y = x.getOrElse(1.414) // y inferred as Double, assigned 1.414
      
      let a: Int? = 5
      
      let b: Double = a.getOrElse(3.14) // Runtime failure casting 5 to Double
      

      【讨论】:

      • 您不需要为方法指定T。这实际上覆盖了可选的现有T。你可以这样做:func getOrElse(defaultValue: T) -&gt; T 然后 T 指的是可选的实际值类型,你不必类型检查它
      • 谢谢!我从你回复的后半部分推断出这一点。有什么方法可以检查 Optional 的定义以知道泛型类型被定义为 T 吗? (超越简单的基于约定的假设)
      • 如果你在 Xcode 中用命令点击Optional,你会看到它被定义为enum Optional&lt;T&gt;
      • 哦,太好了。我应该猜到了。那里的定义会很有用;文档中还没有很多东西。再次感谢。
      【解决方案5】:

      如果您尝试使用字符串执行此操作,您可以执行此操作..

      string1 = string2.isEmpty ? "Default Value":string2
      

      【讨论】:

        猜你喜欢
        • 2020-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-20
        • 1970-01-01
        • 2019-01-02
        • 1970-01-01
        相关资源
        最近更新 更多