Класс scala.util.Either
Представляет значение одного из двух возможных типов (несовместное объединение). Экземпляр 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]`
| Подтипы | |
|---|---|
| Известные подтипы |
Абстрактные методы
Исходный код
Возвращает true если это Left, false в противном случае.
Left("tulip").isLeft // true
Right("venus fly-trap").isLeft // false
Исходный код
Возвращает true если это Right, false в противном случае.
Left("tulip").isRight // false
Right("venus fly-trap").isRight // true
Конкретные методы
Исходный код
Возвращает 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"
| Параметры значений |
|
|---|---|
| Возвращает |
|
Исходный код
Возвращает false если Left или возвращает результат применения данного предиката к значению Right.
Right(12).exists(_ > 10) // true Right(7).exists(_ > 10) // false Left(12).exists(_ => true) // false
Исходный код
Возвращает 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)
Исходный код
Связывает данную функцию с Right.
| Параметры значений |
|
|---|
Исходный код
Возвращает правое значение, если это правое, или это значение, если это левое
| Пример |
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)
Эквивалентно |
|---|
Исходный код
def fold[C](fa: A => C, fb: B => C): C
Применяет 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"
)
|
Исходный код
Возвращает true если Left или возвращает результат применения данного предиката к значению Right.
Right(12).forall(_ > 10) // true Right(7).forall(_ > 10) // false Left(12).forall(_ => false) // true
Исходный код
Выполняет данную функцию с побочным эффектом, если это Right.
Right(12).foreach(println) // prints "12" Left(12).foreach(println) // doesn't print
| Параметры значений |
|
|---|
Исходный код
def getOrElse[B1 >: B](or: => B1): B1
Возвращает значение из этого Right или заданный аргумент, если это Left.
Right(12).getOrElse(17) // 12 Left(12).getOrElse(17) // 17
Исходный код
Объединяет 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.
Исходный код
Объединяет 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")
Этот метод, и |
|---|
Источник
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")
Источник
Применённая функция, если это Right.
Right(12).map(x => "flower") // Result: Right("flower")
Left(12).map(x => "flower") // Result: Left(12)
Источник
def merge: A
Источник
Возвращает этот 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)
Источник
Если это 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)
|
|---|
Источник
Возвращает Some содержащий значение Right, если оно существует, или None, если это Left.
Right(12).toOption // Some(12) Left(12).toOption // None
Источник
Возвращает Seq содержащий значение Right, если оно существует, или пустое Seq если это Left.
Right(12).toSeq // Seq(12) Left(12).toSeq // Seq()
Источник
Наследованные методы
Источник
Метод, который должен вызываться из каждого хорошо спроектированного метода equals, который открыт для переопределения в подклассе. См. Programming in Scala, Глава 28 для обсуждения и проектирования.
| Параметры |
|
|---|---|
| Возвращает | true, если этот экземпляр потенциально может быть равен |
| Наследуется от | Equals |
Источник
def productArity: Int
Размер этого продукта.
| Возвращает | для продукта |
|---|---|
| Наследуется от | Product |
Источник
n-й элемент этого продукта, нумерация с 0. Другими словами, для продукта A(x1, ..., xk), возвращает x(n+1) где 0 <= n < k.
| Параметры |
|
|---|---|
| Возвращает | элемент |
| Исключения |
|
| Наследуется от | Product |
Источник
Имя n-го элемента этого продукта, нумерация с 0. В реализации по умолчанию — пустая строка.
| Параметры |
|
|---|---|
| Возвращает | имя указанного элемента |
| Исключения |
|
| Наследуется от | Product |
Источник
Итератор по именам всех элементов этого продукта.
| Наследуется от | Product |
|---|
Источник
Итератор по всем элементам этого продукта.
| Возвращает | в реализации по умолчанию, |
|---|---|
| Наследуется от | 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