Spec-Zone.ru › Scala 3.2

Класс Either.Either

Объект-компаньон • Исходный код

sealed abstract class Either[+A, +B] extends Product with Serializable

Представляет значение одного из двух возможных типов (разъединённое объединение). Экземпляр Either является экземпляром либо scala.util.Left, либо scala.util.Right.

Распространённое применение Either — это альтернатива scala.Option для работы со значениями, которые могут отсутствовать. В этом использовании scala.None заменяется на scala.util.Left, который может содержать полезную информацию. scala.util.Right занимает место scala.Some. Конвенция предписывает, что Left используется для обозначения ошибки, а Right — для успеха.

Например, вы можете использовать Either[String, Int] для указания того, является ли полученный ввод String или Int.

import scala.io.StdIn._
val in = readLine("Type Either a string or an Int: ")
val result: Either[String,Int] =
  try Right(in.toInt)
  catch {
    case e: NumberFormatException => Left(in)
  }

result match {
  case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}"
  case Left(x)  => s"You passed me the String: $x"
}

Either имеет правую предвзятость, что означает, что Right считается случаем по умолчанию для обработки. Если это Left, операции, такие как map и flatMap возвращают значение Left без изменений:

def doubled(i: Int) = i * 2
Right(42).map(doubled) // Right(84)
Left(42).map(doubled)  // Left(42)

Поскольку Either определяет методы map и flatMap, его также можно использовать в выражениях for:

val right1 = Right(1)   : Right[Double, Int]
val right2 = Right(2)
val right3 = Right(3)
val left23 = Left(23.0) : Left[Double, Int]
val left42 = Left(42.0)

for {
  x <- right1
  y <- right2
  z <- right3
} yield x + y + z // Right(6)

for {
  x <- right1
  y <- right2
  z <- left23
} yield x + y + z // Left(23.0)

for {
  x <- right1
  y <- left23
  z <- right2
} yield x + y + z // Left(23.0)

// Guard expressions are not supported:
for {
  i <- right1
  if i > 0
} yield i
// error: value withFilter is not a member of Right[Double,Int]

// Similarly, refutable patterns are not supported:
for (x: Int <- right1) yield x
// error: value withFilter is not a member of Right[Double,Int]

Поскольку выражения for с for используют map и flatMap, типы параметров функций, используемых в выражении, должны быть выведены. Эти типы ограничены значениями Either. В частности, из-за правой предвзятости, значениям Left может потребоваться явный тип аргумента для параметра типа B, правого значения. В противном случае он может быть выведен как Nothing.

for {
  x <- left23
  y <- right1
  z <- left42  // type at this position: Either[Double, Nothing]
} yield x + y + z
//            ^
// error: ambiguous reference to overloaded definition,
// both method + in class Int of type (x: Char)Int
// and  method + in class Int of type (x: Byte)Int
// match argument types (Nothing)

for (x <- right2 ; y <- left23) yield x + y  // Left(23.0)
for (x <- right2 ; y <- left42) yield x + y  // error

for {
  x <- right1
  y <- left42  // type at this position: Either[Double, Nothing]
  z <- left23
} yield x + y + z
// Left(42.0), but unexpectedly a `Either[Double,String]`
Надтипы
интерфейс Serializable
тракт Product
тракт Equals
класс Object
тракт Matchable
класс Any
Известные подтипы
класс Left[A, B]
класс Right[A, B]

Абстрактные методы

Источник
def isLeft: Boolean

Возвращает true если это Left, false в противном случае.

Left("tulip").isLeft // true
Right("venus fly-trap").isLeft // false

Источник
def isRight: Boolean

Возвращает true если это Right, false в противном случае.

Left("tulip").isRight // false
Right("venus fly-trap").isRight // true

Конкретные методы

Источник
final def contains[B1 >: B](elem: B1): Boolean

Возвращает true если это Right и его значение равно elem (как определено ==), возвращает false в противном случае.

// Returns true because value of Right is "something" which equals "something".
Right("something") contains "something"

// Returns false because value of Right is "something" which does not equal "anything".
Right("something") contains "anything"

// Returns false because it's not a Right value.
Left("something") contains "something"
Параметры значения
elem

тестируемый элемент.

Возвращает

true если это Right значение, равное elem.

Источник
def exists(p: B => Boolean): Boolean

Возвращает false если Left или возвращает результат применения заданного предиката к значению Right.

Right(12).exists(_ > 10)   // true
Right(7).exists(_ > 10)    // false
Left(12).exists(_ => true) // false

Источник
def filterOrElse[A1 >: A](p: B => Boolean, zero: => A1): Either[A1, B]

Возвращает Right со значением Right если это Right и заданный предикат p выполняется для правого значения, или Left(zero) если это Right и заданный предикат p не выполняется для правого значения, или Left со значением Left если это Left.

Right(12).filterOrElse(_ > 10, -1)   // Right(12)
Right(7).filterOrElse(_ > 10, -1)    // Left(-1)
Left(7).filterOrElse(_ => false, -1) // Left(7)

Источник
def flatMap[A1 >: A, B1](f: B => Either[A1, B1]): Either[A1, B1]

Связывает заданную функцию с Right.

Параметры значения
f

Функция для связывания с Right.

Источник
def flatten[A1 >: A, B1](implicit ev: B <:< Either[A1, B1]): Either[A1, B1]

Возвращает правое значение, если это право или это значение, если это лево

Пример
val  l: Either[String, Either[String, Int]] = Left("pancake")
val rl: Either[String, Either[String, Int]] = Right(Left("flounder"))
val rr: Either[String, Either[String, Int]] = Right(Right(7))
l.flatten //Either[String, Int]: Left("pancake")
rl.flatten //Either[String, Int]: Left("flounder")
rr.flatten //Either[String, Int]: Right(7)

Эквивалентно flatMap(id => id)

Источник
def fold[C](fa: A => C, fb: B => C): C

Применяет fa если это Left или fb если это Right.

Параметры значения
fa

функция для применения, если это Left

fb

функция для применения, если это Right

Возвращает

результаты применения функции

Пример
val result = util.Try("42".toInt).toEither
result.fold(
  e => s"Operation failed with $e",
  v => s"Operation produced value: $v"
)

Источник
def forall(f: B => Boolean): Boolean

Возвращает true если Left или возвращает результат применения заданного предиката к значению Right.

Right(12).forall(_ > 10)    // true
Right(7).forall(_ > 10)     // false
Left(12).forall(_ => false) // true

Источник
def foreach[U](f: B => U): Unit

Выполняет заданную функцию с побочным эффектом, если это Right.

Right(12).foreach(println) // prints "12"
Left(12).foreach(println)  // doesn't print
Параметры значения
f

Функция с побочным эффектом для выполнения.

Источник
def getOrElse[B1 >: B](or: => B1): B1

Возвращает значение из этого Right или заданный аргумент, если это Left.

Right(12).getOrElse(17) // 12
Left(12).getOrElse(17)  // 17

Источник
def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1]

Объединяет Either через Left.

Этот метод требует, чтобы левая часть этого Either сама была типом Either. То есть это должен быть какой-то тип, например:

Either[Either[C, B], B]

(который соблюдает ограничения параметров типа, показанные ниже.)

Если этот экземпляр Left[Either[C, B]], то содержащееся Either[C, B] будет возвращено, в противном случае это значение будет возвращено без изменений.

Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower")
Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12)
Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy")

Этот метод, и joinRight, аналогичны Option#flatten.

Источник
def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C]

Объединяет Either через Right.

Этот метод требует, чтобы правая часть этого Either сама была типом Either. То есть это должен быть какой-то тип, например:

Either[A, Either[A, C]]

(который соблюдает ограничения параметров типа, показанные ниже.)

Если этот экземпляр Right[Either[A, C]], то содержащееся Either[A, C] будет возвращено, в противном случае это значение будет возвращено без изменений.

Пример
Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12)
Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower")
Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower")

Этот метод, и joinLeft, аналогичны Option#flatten

Источник
def left: LeftProjection[A, B]

Проектирует этот Either в виде Left.

Это позволяет использовать for-понимания над левой стороной Either экземпляров, обращая обычный правосторонний уклон Either.

Например

for (s <- Left("flower").left) yield s.length // Left(6)

Продолжая аналогию с scala.Option, LeftProjection заявляет, что Left должно быть аналогично Some в некотором коде.

// using Option
def interactWithDB(x: Query): Option[Result] =
  try Some(getResultFromDatabase(x))
  catch {
    case _: SQLException => None
  }

// this will only be executed if interactWithDB returns a Some
val report = for (result <- interactWithDB(someQuery)) yield generateReport(result)
report match {
  case Some(r) => send(r)
  case None    => log("report not generated, not sure why...")
}

// using Either
def interactWithDB(x: Query): Either[Exception, Result] =
  try Right(getResultFromDatabase(x))
  catch {
    case e: SQLException => Left(e)
  }

 // run a report only if interactWithDB returns a Right
 val report = for (result <- interactWithDB(someQuery)) yield generateReport(result)
 report match {
   case Right(r) => send(r)
   case Left(e)  => log(s"report not generated, reason was $e")
 }
 // only report errors
 for (e <- interactWithDB(someQuery).left) log(s"query failed, reason was $e")

Источник
def map[B1](f: B => B1): Either[A, B1]

Применённая функция, если это Right.

Right(12).map(x => "flower") // Result: Right("flower")
Left(12).map(x => "flower")  // Result: Left(12)

Источник
def merge: A

Неявное добавление MergeableEither

Источник
def orElse[A1 >: A, B1 >: B](or: => Either[A1, B1]): Either[A1, B1]

Возвращает этот Right или заданный аргумент, если это Left.

Right(1) orElse Left(2) // Right(1)
Left(1) orElse Left(2)  // Left(2)
Left(1) orElse Left(2) orElse Right(3) // Right(3)

Источник
def swap: Either[B, A]

Если это Left, возвращает левое значение в Right или наоборот.

Пример
val left: Either[String, Int]  = Left("left")
val right: Either[Int, String] = left.swap // Result: Right("left")
val right = Right(2)
val left  = Left(3)
for {
  r1 <- right
  r2 <- left.swap
} yield r1 * r2 // Right(6)

Источник
def toOption: Option[B]

Возвращает Some содержащий значение Right, если оно существует, или None, если это Left.

Right(12).toOption // Some(12)
Left(12).toOption  // None

Источник
def toSeq: Seq[B]

Возвращает Seq содержащий значение Right, если оно существует, или пустое Seq если это Left.

Right(12).toSeq // Seq(12)
Left(12).toSeq  // Seq()

Источник
def toTry(implicit ev: A <:< Throwable): Try[B]

Наследованные методы

Источник
def canEqual(that: Any): Boolean

Метод, который должен вызываться из каждого хорошо спроектированного метода equals, который открыт для переопределения в подклассе. См. Programming in Scala, Глава 28 для обсуждения и проектирования.

Параметры
that

значение, которое проверяется на возможную равенство

Возвращает

true, если этот экземпляр потенциально может быть равен that, иначе false

Наследуется от Equals

Источник
def productArity: Int

Размер этого продукта.

Возвращает

для продукта A(x1, ..., xk), возвращает k

Наследуется от Product

Источник
def productElement(n: Int): Any

n-й элемент этого продукта, нумерация с 0. Другими словами, для продукта A(x1, ..., xk), возвращает x(n+1) где 0 <= n < k.

Параметры
n

индекс возвращаемого элемента

Возвращает

элемент n элементов после первого элемента

Исключения
IndexOutOfBoundsException

если n выходит за пределы диапазона (n < 0 || n >= productArity).

Наследуется от Product

Источник
def productElementName(n: Int): String

Имя n-го элемента этого продукта, нумерация с 0. В реализации по умолчанию — пустая строка.

Параметры
n

индекс искомого имени элемента

Возвращает

имя указанного элемента

Исключения
IndexOutOfBoundsException

если n выходит за пределы диапазона (n < 0 || n >= productArity).

Наследуется от Product

Источник
def productElementNames: Iterator[String]

Итератор по именам всех элементов этого продукта.

Наследуется от Product

Источник
def productIterator: Iterator[Any]

Итератор по всем элементам этого продукта.

Возвращает

в реализации по умолчанию, Iterator[Any]

Наследуется от Product

Источник
def productPrefix: String

Строка, используемая в методах toString производных классов. Реализации могут переопределить этот метод, чтобы добавить строковый префикс к результату методов toString.

Возвращает

в реализации по умолчанию — пустая строка

Наследуется от Product

© 2002-2022 EPFL, with contributions from Lightbend.
Licensed under the Apache License, Version 2.0.
https://scala-lang.org/api/3.2.0/scala/util/Either.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API