Scala 向右映射或 return 向左映射
Scala Either map Right or return Left
是否可以像 Option
一样处理 Either
?在 Option
中,我有一个 getOrElse
函数,在 Either
中,我想 return Left
或处理 Right
。我正在寻找没有任何样板的最快方法,例如:
val myEither:Either[String, Object] = Right(new Object())
myEither match {
case Left(leftValue) => value
case Right(righValue) =>
"Success"
}
我想你可以按照下面的方式做。
def foo(myEither: Either[String, Object]) =
myEither.right.map(rightValue => "Success")
您可以使用 .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
编辑:
Re-reading 你的问题我不清楚你是想 return Left
中的值还是另一个(在别处定义的)
如果是前者,您可以将 identity
传递给 .fold
,但这可能会将 return 类型更改为 Any
:
scala> r.fold(identity, _ => "Success")
res9: Any = Success
cchantep 和 Marth 都是解决您当前问题的好方法。但更广泛地说,很难将 Either 视为与 Option
完全类似的东西,尤其是在让您表达可能会失败的计算序列以供理解时。要么有一个投影API(在cchantep的解决方案中使用),但它有点坏了。 (其中任何一个的预测都会因守卫、模式匹配或变量赋值的理解而中断。)
FWIW,我写了一篇 library to solve this problem. It augments Either with this API。您为您的 Eithers 定义了一个“偏见”。 “右偏”意味着普通流(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" )
更有用的是,您现在可以将 Either 视为真正的 scala monad,即使用 flatMap、map、filter 和理解:
val myEither : Either[String, Point] = ???
val nextEither = myEither.map( _.x ) // Either[String,Int]
或
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)
}
}
如果所有处理步骤都成功,locPopPair
将是 Right[Long]
。如果有任何问题,这将是第一个 Left[String]
遇到的。
它稍微复杂一些,但定义一个空标记是个好主意。让我们看一下上述 for 理解的细微变化:
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
如果测试 p.x > 1000
失败会怎样?我们想要 return 一些 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)
}
}
现在,如果 p.x > 1000
测试失败,将不会有异常,locPopPair
将只是 Left("EMPTY")
。
在 Scala 2.12 中,
所以你可以做到
myEither.map(_ => "Success").merge
如果您觉得它比 fold
更具可读性。
在 scala 2.13 中,您可以使用 myEither.getOrElse
Right(12).getOrElse(17) // 12
Left(12).getOrElse(17) // 17
是否可以像 Option
一样处理 Either
?在 Option
中,我有一个 getOrElse
函数,在 Either
中,我想 return Left
或处理 Right
。我正在寻找没有任何样板的最快方法,例如:
val myEither:Either[String, Object] = Right(new Object())
myEither match {
case Left(leftValue) => value
case Right(righValue) =>
"Success"
}
我想你可以按照下面的方式做。
def foo(myEither: Either[String, Object]) =
myEither.right.map(rightValue => "Success")
您可以使用 .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
编辑:
Re-reading 你的问题我不清楚你是想 return Left
中的值还是另一个(在别处定义的)
如果是前者,您可以将 identity
传递给 .fold
,但这可能会将 return 类型更改为 Any
:
scala> r.fold(identity, _ => "Success")
res9: Any = Success
cchantep 和 Marth 都是解决您当前问题的好方法。但更广泛地说,很难将 Either 视为与 Option
完全类似的东西,尤其是在让您表达可能会失败的计算序列以供理解时。要么有一个投影API(在cchantep的解决方案中使用),但它有点坏了。 (其中任何一个的预测都会因守卫、模式匹配或变量赋值的理解而中断。)
FWIW,我写了一篇 library to solve this problem. It augments Either with this API。您为您的 Eithers 定义了一个“偏见”。 “右偏”意味着普通流(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" )
更有用的是,您现在可以将 Either 视为真正的 scala monad,即使用 flatMap、map、filter 和理解:
val myEither : Either[String, Point] = ???
val nextEither = myEither.map( _.x ) // Either[String,Int]
或
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)
}
}
如果所有处理步骤都成功,locPopPair
将是 Right[Long]
。如果有任何问题,这将是第一个 Left[String]
遇到的。
它稍微复杂一些,但定义一个空标记是个好主意。让我们看一下上述 for 理解的细微变化:
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
如果测试 p.x > 1000
失败会怎样?我们想要 return 一些 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)
}
}
现在,如果 p.x > 1000
测试失败,将不会有异常,locPopPair
将只是 Left("EMPTY")
。
在 Scala 2.12 中,
所以你可以做到
myEither.map(_ => "Success").merge
如果您觉得它比 fold
更具可读性。
在 scala 2.13 中,您可以使用 myEither.getOrElse
Right(12).getOrElse(17) // 12
Left(12).getOrElse(17) // 17