有没有简洁的方法来“反转”一个选项?

时间:2018-03-23 16:40:06

标签: scala optional

假设我有一个可以接受可选参数的函数,如果参数为Some,我想返回None,如果参数为{{1},我想返回None }:

Some

所以我想做的就是def foo(a: Option[A]): Option[B] = a match { case Some(_) => None case None => Some(makeB()) } 的倒数。 map的变体不适用,因为如果它存在,它们会保留orElse的值。

有没有比a更简洁的方法呢?

3 个答案:

答案 0 :(得分:8)

折叠比模式匹配更简洁

 val op:Option[B] = ...

 val inv = op.fold(Option(makeB()))(_ => None)

答案 1 :(得分:6)

这个答案概述:

  1. 使用fold
  2. 的单线解决方案
  3. 使用fold
  4. 的小演示
  5. 讨论为什么fold - 解决方案可能if-else - 解决方案一样“显而易见”。
  6. <强>解决方案

    您始终可以使用foldOption[A]转换为您想要的内容:

    a.fold(Option(makeB())){_ => Option.empty[B]}
    

    <强>演示

    这是一个包含所有必要类型定义的完整可运行示例:

    class A
    class B
    def makeB(): B = new B
    
    def foo(a: Option[A]): Option[B] = a match {
      case Some(_) => None
      case None    => Some(makeB())
    }
    
    def foo2(a: Option[A]): Option[B] = 
      a.fold(Option(makeB())){_ => Option.empty[B]}
    
    println(foo(Some(new A)))
    println(foo(None))
    println(foo2(Some(new A)))
    println(foo2(None))
    

    输出:

    None
    Some(Main$$anon$1$B@5fdef03a)
    None
    Some(Main$$anon$1$B@48cf768c)
    

    为什么fold只有似乎不那么直观

    在评论中,@ TheArchetypalPaul评论说fold似乎“不那么明显”而不是if-else解决方案。

    我认为这主要是由于布尔值存在特殊if-else语法而产生的工件。

    如果有类似标准

    的话
    def ifNone[A, B](opt: Option[A])(e: => B) = new {
      def otherwise[C >: B](f: A => C): C = opt.fold((e: C))(f)
    }
    

    语法可以像这样使用:

    val optStr: Option[String] = Some("hello")
    
    val reversed = ifNone(optStr) { 
      Some("makeB") 
    } otherwise {
      str => None
    }
    

    更重要的是,如果在过去半个世纪发明的每种编程语言的每一个介绍的第一页上都提到了这种语法,那么ifNone-otherwise解决方案(即fold) ,对大多数人来说看起来更自然。

    实际上,Option.fold方法是Option[T]类型的消除器:只要我们有Option[T]并希望获得A在其中,最明显的预期应该是fold(a)(b) a: Ab: T => A。与使用if-else - 语法(仅仅是惯例)对布尔值进行特殊处理相比,fold方法非常基础,必须在那里可以从第一原则中得出。

答案 2 :(得分:1)

我想出了这个定义a.map(_ => None).getOrElse(Some(makeB()))

scala> def f[A](a: Option[A]) = a.map(_ => None).getOrElse(Some(makeB()))
f: [A](a: Option[A])Option[makeB]

scala> f(Some(44))
res104: Option[makeB] = None

scala> f(None)
res105: Option[makeB] = Some(makeB())