Как инициализировать Either to Right и указать тип Left? - PullRequest
6 голосов
/ 09 июня 2019

Я хотел бы инициализировать Either до 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]

Я, очевидно, вынужден подробно указать тип обеих сторон Either:

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

Аналогичным образом, я могу использовать Option.empty[Int] для инициализации None как Option[Int], будет ли способ инициализировать Left("smthg") как Either[String, Int]?

Ответы [ 2 ]

11 голосов
/ 09 июня 2019

Начиная с Scala 2.13, Left поставляется с методом Left#withRight, который позволяет повысить Left[A, Nothing] до Either[A, B]:

Left("smthg").withRight[Int]
// Either[String, Int] = Left("smthg")
Left("smthg")
// Left[String, Nothing] = Left("smthg")

То же самое касается стороны Right и withLeft:

Right(42).withLeft[String]
// Either[String, Int] = Right(42)

, который дает в вашем случае:

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)
7 голосов
/ 09 июня 2019

В дополнение к ответу Ксавьера cats также предоставляют служебные методы для создания Either, например, мы можем сделать:

import cats.implicits._

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

val left: = "hello cats".asLeft[Int] // Either[String, Int]

Это может быть полезно, если в нашем проекте используется 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)

}
...