3
val one: Option[Int] = None    
val two = Some(2)

Option(one.getOrElse(two.getOrElse(null))) // Gives me Some(2) which I want

val one = Some(1)
val two = None

Option(one.getOrElse(two.getOrElse(null))) // Gives me Some(1) which I want

val one: Option[Int] = None
val two: Option[Int] = None

Option(one.getOrElse(two.getOrElse(null))) // Gives me None which I want

val one = Some(1)
val two = Some(2)

Option(one.getOrElse(two.getOrElse(null))) // Gives me Some(1) when I want an exception

我简要研究了 Either 类型,但它似乎是用于“表示两种可能类型之一的值”。我是否缺少一些数据结构或 Monad?本质上,我想要一个明确的(如果两者都有价值,则抛出错误)如果可用,则获取其中一个或获取 None

4

9 回答 9

10

我不知道有任何预先构建的功能,所以这里有一个函数:

def xor[T](x: Option[T], y: Option[T]): Option[T] = (x, y) match {
    case (Some(_), None) => x
    case (None, Some(_)) => y
    case (None, None) => None
    case _ => throw new Exception()
}
于 2014-09-26T17:50:41.727 回答
4

这是我的功能版本

val options = Seq(one, two).flatten
if (options.size > 1) throw new Exception("two options were provided")
options.headOption
于 2014-09-26T17:52:57.507 回答
4
def xor[T](a: Option[T], b: Option[T]) = 
    a orElse b ensuring (_ => a zip b isEmpty)
于 2014-09-26T18:32:15.967 回答
3

对于简单的案例,我可能会去老学校。

scala> implicit class optxor[A](val opt: Option[A]) extends AnyVal {
     | def xor(other: Option[A]) = if (opt.isEmpty) other else if (other.isEmpty) opt else ??? }
defined class optxor

scala> one xor two
res18: Option[Int] = Some(2)

scala> two xor three
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
  at optxor$.xor$extension(<console>:8)
  ... 33 elided
于 2014-09-26T19:14:09.310 回答
1

我会使用像 gzou 回答的模式匹配函数来解决这个问题,但这里有一个衬里:

one.map{x => two.foreach(y => throw new Exception("both defined")); x}.orElse(two)
于 2014-09-27T04:33:17.497 回答
1

我们可以将 2 Options 组合为Iterablewith运算符,从而在可迭代对象而不是选项元组上进行模式匹配:Option++

optionA ++ optionB match {
  case Seq(x, y) => throw new Exception
  case x => x.headOption
}
// None and None       => None
// Some(5) and None    => Some(5)
// None and Some(5)    => Some(5)
// Some(5) and Some(3) => Exception

请注意headOption,它可以很好地处理具有 1 个元素的列表和空列表。

于 2019-01-23T22:35:40.133 回答
0

或者,

scala> val one: Option[Int] = None
one: Option[Int] = None

scala> val two = Option(2)
two: Option[Int] = Some(2)

scala> val three = Option(3)
three: Option[Int] = Some(3)

scala> (for (_ <- one; _ <- two) yield ???) orElse one orElse two
res0: Option[Int] = Some(2)

scala> (for (_ <- three; _ <- two) yield ???) orElse three orElse two
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
  at $anonfun$1$$anonfun$apply$1.apply(<console>:10)
  at $anonfun$1$$anonfun$apply$1.apply(<console>:10)
  at scala.Option.map(Option.scala:145)
  at $anonfun$1.apply(<console>:10)
  at $anonfun$1.apply(<console>:10)
  at scala.Option.flatMap(Option.scala:170)
  ... 33 elided

去糖

scala> one flatMap (_ => two) map (_ => ???) orElse one orElse two
res3: Option[Int] = Some(2)

但习惯上很难想象做这些。

于 2014-09-26T18:33:20.040 回答
0

这个怎么样?

import scala.util.Try

object XorOption {

  def xorOptions[T](one: Option[T], two: Option[T]): Try[Option[T]] = {
    Try {
      for (x <- one; y <- two) throw new RuntimeException
      one.orElse(two)
    }
  }

  def main(args: Array[String]) {
    val testData = List(
      (None, None),
      (None, Some(2)),
      (Some(1), None),
      (Some(1), Some(2)))

    for (t <- testData) {
      println(t + " => " + xorOptions(t._1, t._2))
    }

  }

}

输出:

(None,None) => Success(None)
(None,Some(2)) => Success(Some(2))
(Some(1),None) => Success(Some(1))
(Some(1),Some(2)) => Failure(java.lang.RuntimeException)
于 2014-09-27T19:38:15.667 回答
0
List(Some(1), Some(2)).flatten match {
   case x :: Nil => Some(x)
   case Nil => None
   case _ => throw new Exception
}
于 2014-09-27T20:46:46.050 回答