Хитрость в том, что не получает пары «имя состояния / значение состояния» из Either
. Они должны храниться внутри. Если вы хотите, вы можете преобразовать тип Either
во что-то другое (например, Option
, отбросив все, что у вас было слева), но не уничтожайте эффект. Что-то должно быть там, чтобы показать, что декодирование могло быть неудачным;это может быть Either
, Option
, Try
и т. д. В конце концов вы соответственно обработаете левый и правый регистр, но это должно произойти как можно позже.
Давайте рассмотрим следующий тривиальный пример:
val x: Either[String, Int] = Right(42)
def f(i: Int) = i + 1
Вы можете утверждать, что вам нужно получить 42 из Right
, чтобы вы могли передать его в f
. Но это не правильно. Давайте перепишем пример:
val x: Either[String, Int] = someFunction()
Что теперь? Мы не знаем, есть ли у нас Left
или Right
в значении x
, поэтому мы не можем «вытащить это». Какое целое число вы бы получили, если это Left
? (если у вас действительно есть целочисленное значение для использования в этом случае, это вполне справедливо, и я рассмотрю этот вариант использования чуть позже)
Вместо этого вам нужно будет сохранить эффект (в данном случае Either
), и вам необходимо продолжить работу в контексте этого эффекта. Это должно показать, что в вашей программе был пункт (в данном случае someFunction()
, или расшифровка в вашем исходном вопросе), который мог пойти не так.
Так что если вы хотите применить f
к вашемупотенциальное целое число, вам нужно map
эффект с ним (мы можем сделать это, потому что Either
является функтором, но это деталь, которая, вероятно, выходит за рамки этого ответа):
val x: Either[String, Int] = Right(42)
def f(i: Int) = i + 1
val y = x.map(value => f(value)) // Right(43)
val y = x.map(f) // shorter, point-free notation
и
val x: Either[String, Int] = someFunction()
def f(i: Int) = i + 1
// either a Left with some String, or a Right with some integer increased by 1
val y = x.map(f)
Затем, в самом конце цепочки вычислений, вы можете обрабатывать случаи Left
и Right
;например, если вы обрабатывали HTTP-запрос, то в случае Left
вы могли бы вернуть 500, а в случае Right
вернуть 200.
Для обращения к сценарию использования с указанным значением по умолчаниюраньше - если вы действительно хотите это сделать, избавиться от Left
и в этом случае разрешить какое-то значение (например, 0), тогда вы можете использовать fold
:
def f(i: Int) = i + 1
// if x = Left, then z = 0
// if x = Right, then z = x + 1
val z = x.fold(_ => 0, i => i + 1)