给出Either[String,Int]
:
scala> val z: Either[String, Int] = Right(100)
z: Either[String,Int] = Right(100)
我可以用flatMap
编写以下代码:
scala> z.right.flatMap(x => if(x == 100) Left("foo") else Right(x))
res14: scala.util.Either[String,Int] = Left(foo)
但是,我对for comprehension
版本做错了什么?
scala> for {
| a <- z.right
| _ <- if(a == 100) Left("foo") else Right(a)
| } yield a
<console>:11: error: value map is not a member of Product with Serializable
with scala.util.Either[String,Int]
_ <- if(a == 100) Left("foo") else Right(a)
^
答案 0 :(得分:3)
if(a == 100) Left("foo") else Right(a)
是Either[String, Int]
,而不是LeftProjection
或RightProjection
,因此它没有map
或flatMap
。你也需要预测它:
for {
a <- z.right
_ <- (if(a == 100) Left("foo") else Right(a)).right
} yield a
这与单线的区别在于单线相当于:
for {
a <- z.right
} yield (if(a == 100) Left("foo") else Right(a))
..最后没有额外的map
。
答案 1 :(得分:1)
我认为这个问题的公认答案现在已经过时了。
因为scala 2.12
,Either
默认为右偏。
因此,Either
已定义map
和flatMap
。
/** Binds the given function across `Left`.
*
* {{{
* Left(12).left.flatMap(x => Left("scala")) // Left("scala")
* Right(12).left.flatMap(x => Left("scala")) // Right(12)
* }}}
* @param f The function to bind across `Left`.
*/
def flatMap[A1, B1 >: B](f: A => Either[A1, B1]): Either[A1, B1] = e match {
case Left(a) => f(a)
case _ => e.asInstanceOf[Either[A1, B1]]
}
/** Maps the function argument through `Left`.
*
* {{{
* Left(12).left.map(_ + 2) // Left(14)
* Right[Int, Int](12).left.map(_ + 2) // Right(12)
* }}}
*/
def map[A1](f: A => A1): Either[A1, B] = e match {
case Left(a) => Left(f(a))
case _ => e.asInstanceOf[Either[A1, B]]
}
因此,您不必使用RightProjection
,因为默认情况下Either
右偏。所以下面的代码可以工作。
val z: Either[String, Int] = Right(100)
val ans = for {
a <- z
_ <- if (a == 100) Left("foo") else Right(a)
} yield a
希望这有帮助。