scala Scala要么向右映射要么向左返回
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34545394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala Either map Right or return Left
提问by Micha? Jurczuk
Is it possible to handle Eitherin similar way to Option? In Option, I have a getOrElsefunction, in EitherI want to return Leftor process Right. I'm looking for the fastest way of doing this without any boilerplate like:
是否可以以Either类似的方式处理Option?在Option,我有一个getOrElse函数,在Either我想返回Left或处理Right。我正在寻找没有任何样板文件的最快方法:
val myEither:Either[String, Object] = Right(new Object())
myEither match {
case Left(leftValue) => value
case Right(righValue) =>
"Success"
}
回答by Alexey Romanov
In Scala 2.12,
在 Scala 2.12 中,
两者都是右偏的,这意味着 Right 被假定为要对其进行操作的默认情况。如果是Left,map、flatMap、...等操作返回Left值不变
so you can do
所以你可以做
myEither.map(_ => "Success").merge
if you find it more readable than fold.
如果你发现它比fold.
回答by Marth
You can use X,fb:B=>X):X" rel="noreferrer">.fold:
您可以使用X,fb:B=>X):X" rel="noreferrer">.fold:
scala> val r: Either[Int, String] = Right("hello")
r: Either[Int,String] = Right(hello)
scala> r.fold(_ => "got a left", _ => "Success")
res7: String = Success
scala> val l: Either[Int, String] = Left(1)
l: Either[Int,String] = Left(1)
scala> l.fold(_ => "got a left", _ => "Success")
res8: String = got a left
Edit:
编辑:
Re-reading your question it's unclear to me whether you want to return the value in the Leftor another one (defined elsewhere)
If it is the former, you can pass identityto .fold, however this might change the return type to Any:
重新阅读您的问题,我不清楚您是要返回 中的值Left还是另一个(在其他地方定义)中的值,
如果是前者,则可以传递identity给.fold,但这可能会将返回类型更改为Any:
scala> r.fold(identity, _ => "Success")
res9: Any = Success
回答by Steve Waldman
Both cchantep's and Marth's are good solutions to your immediate problem. But more broadly, it's difficult to treat Either as something fully analogous to Option, particularly in letting you express sequences of potentially failable computations for comprehensions. Either has a projection API (used in cchantep's solution), but it is a bit broken. (Either's projections break in for comprehensions with guards, pattern matching, or variable assignment.)
ccantep 和 Marth 都是解决您眼前问题的好方法。但更广泛地说,很难将任何东西视为完全类似于 的东西Option,尤其是在让您表达可能会失败的推导式计算序列方面。要么有一个投影 API(在 cchantep 的解决方案中使用),但它有点坏。(任何一种预测都可以通过保护、模式匹配或变量赋值来理解。)
FWIW, I've written a libraryto solve this problem. It augments Either with this API. You define a "bias" for your Eithers. "Right bias" means that ordinary flow (map, get, etc) is represented by a Rightobject while Leftobjects represent some kind of problem. (Right bias is conventional, although you can also define a left bias if you prefer.) Then you can treat the Eitherlike an Option; it offsers a fully analogous API.
FWIW,我写了一个库来解决这个问题。它通过此 API增强了任何一种。你为你的两个人定义了一个“偏见”。“正确偏差”意味着普通流(map、get 等)由Right对象表示,而Left对象表示某种问题。(右偏见是传统的,但你也可以,如果你喜欢定义左偏。)然后,你可以把对Either像Option; 它提供了一个完全类似的 API。
import com.mchange.leftright.BiasedEither
import BiasedEither.RightBias._
val myEither:Either[String, Object] = ...
val o = myEither.getOrElse( "Substitute" )
More usefully, you can now treat Either like a true scala monad, i.e. use flatMap, map, filter, and for comprehensions:
更有用的是,您现在可以像对待真正的 scala monad 一样对待任何一个,即使用 flatMap、map、filter 和 for comprehensions:
val myEither : Either[String, Point] = ???
val nextEither = myEither.map( _.x ) // Either[String,Int]
or
或者
val myEither : Either[String, Point] = ???
def findGalaxyAtPoint( p : Point ) : Either[String,Galaxy] = ???
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p )
} yield {
(p, g.population)
}
}
If all processing steps succeeded, locPopPairwill be a Right[Long]. If anything went wrong, it will be the first Left[String]encountered.
如果所有处理步骤都成功,locPopPair将是一个Right[Long]. 如果出了什么问题,那将是第一个Left[String]遇到的。
It's slightly more complex, but a good idea to define an empty token. Let's look at a slight variation on the for comprehension above:
它稍微复杂一些,但定义一个空标记是个好主意。让我们看一下上面 for comprehension 的细微变化:
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
What would happen if the test p.x > 1000failed? We'd want to return some Leftthat signifies "empty", but there is no universal appropriate value (not all Left's are Left[String]. As of now, what would happen is the code would throw a NoSuchElementException. But we can specify an empty token ourselves, as below:
如果测试p.x > 1000失败会发生什么?我们想要返回一些Left表示“空”的值,但没有通用的合适值(并非所有Left的都是Left[String]。截至目前,会发生的是代码会抛出NoSuchElementException。但我们可以自己指定一个空标记,如下:
import com.mchange.leftright.BiasedEither
val RightBias = BiasedEither.RightBias.withEmptyToken[String]("EMPTY")
import RightBias._
val myEither : Either[String, Point] = ???
def findGalaxyAtPoint( p : Point ) : Either[String,Galaxy] = ???
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
Now, if the p.x > 1000test fails, there will be no Exception, locPopPairwill just be Left("EMPTY").
现在,如果p.x > 1000测试失败,则不会有异常,locPopPair只有Left("EMPTY").
回答by cchantep
I guess you can do as follows.
我想你可以做如下。
def foo(myEither: Either[String, Object]) =
myEither.right.map(rightValue => "Success")

