我正在使用Scala 2.11.8
我有这段代码
run
IDE(IntelliJ 2017.1)未显示任何错误。但是当我从SBT编译时。它说
val i1 = Either[ErrorCode, Person] = getMaybePerson().toRight(ErrorCode.NOTFOUND)
val i2 = Either[ErrorCode, (Int, FiniteDuration)] = getMaybeConfig().toRight(ErrorCode.NOCONFIG)
for {
a <- i1.right
(c, d) <- i2.right
} yield {...}
这让我疯了,因为在REPL。我可以轻松编写此代码。
Warning:(163, 43) `withFilter' method does not yet exist on scala.util.Either.RightProjection[ErrorCode,(Int, scala.concurrent.duration.FiniteDuration)], using `filter' method instead
(maxReward, checkDuration) <- i2.right
Error:(163, 10) constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, scala.concurrent.duration.FiniteDuration)]
(maxReward, checkDuration) <- i2.right
答案 0 :(得分:3)
简短的回答是Either
并不适合理解(至少在scala&lt; 2.11中)。
所以你首先要记住,因为理解是monadic操作map
,flatMap
和withFilter
的语法糖。
特别是,在对提取的值(例如代码中的(c, d) <- i2.right
)进行模式匹配时,会将其替换为(相当于某些内容)
i2.right.withFilter(_.isInstanceOf[Tuple2[A, B]]).map{p =>
val (c, d) = p.asInstanceOf[Tuple2[A, B]]
...
}
现在您可以更清楚地看到问题所在:首先,withFilter
上没有RightProjection
方法,因此它使用filter
代替(如错误语句所示)。然后,filter
方法会输出Option[Either[ErrorCode, (Int, FiniteDuration)]]
,因此您无法将格式与元组进行模式匹配。
如果你可以解决filter
问题,你可能会遇到map
的问题(我知道我做过):
如果您尝试使用分配进行理解:
for {
a <- Right("foo").right
b = a + "bar"
} yield a + b
这也不会起作用,因为它被map
上的Either
电话取代...但由于Either
没有正确偏见(或左 - ),它没有map
方法,因此编译器将丢失(并且如果你不考虑for
是如何去掉的话,会给你一些令人困惑的错误信息。)< / p>
一般情况下,如果要进行某些过滤(包括模式匹配)或分配,则应避免使用Either
进行理解。您可能希望在某些库中考虑一些等效的monad,例如catz或scalaz中的Validation
或\/
。
NB 我说了scala 2.11,因为在scala 2.12中,Either
变得正确偏见,所以上面提到的一些问题消失了,但我还没有我已经尝试过了。