Spec-Zone.ru › Scala 3.1

Класс scala.util.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 компрессии используют 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.1.1/scala/util/Either.html

Spec-Zone.ru

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