用于从两个选项中获取单个选项的惯用scala,如果有两个选项则抛出异常

时间:2014-09-26 17:40:10

标签: scala monads scala-option

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?基本上我想要一个明确的(并且如果两者都有价值则抛出错误)如果可用则获得一个或获得无

9 个答案:

答案 0 :(得分:9)

我不知道任何预先建造的东西,所以这是一个功能:

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()
}

答案 1 :(得分:4)

def xor[T](a: Option[T], b: Option[T]) = 
    a orElse b ensuring (_ => a zip b isEmpty)

答案 2 :(得分: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

答案 3 :(得分:2)

这是我的功能版本

val options = Seq(one, two).flatten
if (options.size > 1) throw new Exception("two options were provided")
options.headOption

答案 4 :(得分:1)

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

one.map{x => two.foreach(y => throw new Exception("both defined")); x}.orElse(two)

答案 5 :(得分: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

desugaring to

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

但在惯用的情况下,很难想象要做其中任何一种。

答案 6 :(得分: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)

答案 7 :(得分:0)

List(Some(1), Some(2)).flatten match {
   case x :: Nil => Some(x)
   case Nil => None
   case _ => throw new Exception
}

答案 8 :(得分:0)

我们可以将2个OptionIterable的{​​{3}}运算符组合为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个元素的列表和空列表。