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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:54:40  来源:igfitidea点击:

Scala Either map Right or return Left

scalaeither

提问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 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对象表示某种问题。(右偏见是传统的,但你也可以,如果你喜欢定义左偏。)然后,你可以把对EitherOption; 它提供了一个完全类似的 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")