Как стать автором
Обновить
9
0
Иван Аникин @ivan_anikin

Mobile DevOps

Отправить сообщение

Дальше можно работать, например, в функциональном стиле, используя:

fun <A, B> Either<A, B>.onLeft(action: (A) -> Unit): Either<A, B>

fun <A, B> Either<A, B>.onRight(action: (B) -> Unit): Either<A, B>

Или использовать функции getOrNull, getOrElse, leftOrNull. В данном случае, get подразумевает получение right, потому что это полезные данные, а это основной сценарий использования.

Проблема решается заданием интерфейса и дополнительными функциями вокруг Either.

Правильный тип выведется за счет типа интерфейса.

interface MyService {
  fun f(): Either<Error, String>
}

enum class Error {
  NO_DATA
}

class MyImpl : MyService {

  fun getData(): String?
  
  override fun f() = either {
    val data = getData()
    ensure(data != null) {
      NO_DATA
    }
    data
  }
}

Более подробно такой подход к работе с ошибками можно в статье из документации Arrow

Можно, если указать явно тип. По умолчанию компилятор выводит тип в лоб.

В твоем примере a имеет тип Either.Left<Nothing?> - потому что указано значение null и не ясно это Int?, String? или Any?, компилятор сам по себе тип не расширяет, поэтому в данном примере он считает, что это самый минимальный тип и это Nothing?.

Для понятности я заменю строчку с нуллом на var a = Either.Left(1) , тогда тип будет Either.Left<Int> это то же самое, что и Either<Int, Nothing> по определению класса Left.

Чтобы все работало так, как ты хочешь, надо явно указать какие типы ожидаются и вывод будет работать.

var a: Either<Int?, String> = Either.Left(null)
a = Either.Right("string")

Если не указывать ни in, ни out, то дженерик является инвариантным.
В таком случае будет между Desk<User> и Desk<Manager> нет никакой иерархии наследования. Экземпляр с наследником создать тоже получится, но без ковариантности не получится его использовать там, где ожидался Desk<User>

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Зарегистрирован
Активность