如何初始化“向右”中的一个并指定“左”的类型?

Xav*_*hot 6 scala either

我想初始化一个Eitherto Left,但这需要指定边的类型Right(反之亦然)。

如果我不这样做,则默认情况下将Right一侧键入Nothing,以便执行以下操作:

List(5, 42, 7).foldLeft(Left("empty")) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}
error: type mismatch;
    found   : scala.util.Right[Nothing,Int]
    required: scala.util.Left[String,Nothing]
Run Code Online (Sandbox Code Playgroud)

我显然被迫冗长地提供的两面类型Either

List(5, 42, 7).foldLeft(Left("empty"): Either[String, Int]) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}
Run Code Online (Sandbox Code Playgroud)

以类似的方式,我可以使用Option.empty[Int]初始化NoneOption[Int],是否可以将初始化Left("smthg")Either[String, Int]

Xav*_*hot 11

开始Scala 2.13Left配备了一个Left#withRight它允许上溯造型方法Left[A, Nothing]Either[A, B]

Left("smthg").withRight[Int]
// Either[String, Int] = Left("smthg")
Left("smthg")
// Left[String, Nothing] = Left("smthg")
Run Code Online (Sandbox Code Playgroud)

这同样适用于Right一侧withLeft

Right(42).withLeft[String]
// Either[String, Int] = Right(42)
Run Code Online (Sandbox Code Playgroud)

在您的情况下:

List(5, 42, 7).foldLeft(Left("empty").withRight[Int]) {
  case (Left(_),  i) => Right(i)
  case (Right(s), i) => Right(s + i)
}
// Either[String, Int] = Right(54)
Run Code Online (Sandbox Code Playgroud)


Krz*_*sik 7

为了补充Xavier的答案,还提供了用于创建的实用方法Either,例如,我们可以执行以下操作:

import cats.implicits._

val right = 7.asRight[String] // Either[String, Int]

val left: = "hello cats".asLeft[Int] // Either[String, Int]
Run Code Online (Sandbox Code Playgroud)

如果我们的项目使用的是Scala 2.12或更低版本,这可能会很有用。

如果我们不需要整个cats库,我们当然可以只为其中一个借用扩展功能

implicit class EitherIdOps[A](private val obj: A) extends AnyVal {

  /** Wrap a value in `Left`. */
  def asLeft[B]: Either[A, B] = Left(obj)

  /** Wrap a value in `Right`. */
  def asRight[B]: Either[B, A] = Right(obj)

}
Run Code Online (Sandbox Code Playgroud)