Ошибка компилятора при использовании Either от dartz

В настоящее время я экспериментирую с фреймворком флаттера и дротиком и наткнулся на, казалось бы, странное поведение, которое я не могу понять. Несмотря на то, что контекст, в котором возникает настоящая проблема, намного сложнее, я даже смог воспроизвести его в чрезвычайно упрощенной демонстрации:

Stream<Either<String, int>> result1 = Stream.fromIterable([1, 2, 3, 4, 5])
    .map((number) => number < 4 ? Right(1) : Left('error'))
    .onErrorReturnWith((error) => Left('error'));

Хотя приведенный выше образец компилируется безоговорочно, я получаю ошибку компиляции для приведенного ниже образца:

Ошибка: значение типа Leftне может быть присвоено переменной типа Right

Stream<Either<String, int>> result2 = Stream.fromIterable([1, 2, 3, 4, 5])
    .map((number) => Right(1))
    .onErrorReturnWith((error) => Left('error'));

Может ли кто-нибудь пролить свет на эту манеру?

################################################ ######

Другой пример:

  Future<Either<String, int>> someWebCall() {
Future<int> response = Future.delayed(Duration(milliseconds: 200), () {
  throw SocketException('Well... ...it happens you know...');
});

return response.then((number) {
  return number > 50.0 ? Right(number) : Left('number is too small...');
}).catchError((error) {
  return Left('are you already questioning the meaning of your life?');
});

}

Это компилируется, но заканчивается ошибкой времени выполнения: тип Future не является подтипом типа Future>

Затем я попытался дать компилятору столько подсказок, сколько смог придумать такой подход:

Future<Either<String, int>> someWebCall() {
Future<int> response = Future.delayed(Duration(milliseconds: 200), () {
  throw SocketException('Well... ...it happens you know...');
});

return response.then<Either<String, int>>((number) {
  return number > 50.0 ? Right(number) : Left('number is too small...') as Either<String, int>;
}).catchError((error) {
  return Left('are you already questioning the meaning of your life?') as Either<String, int>;
});

}

Теперь я получаю: type 'Left' не является подтипом типа 'Either' в приведении типа

Я действительно не могу обдумать это

2 ответа

Решение

Тип функции (number) => Right(1) является Right<dynamic, int> Function(int), что означает, что результирующий поток map звонок - это Stream<Right<dynamic, int>>.

В onErrorReturnWith должен возвращать что-то того же типа, что и элементы вызываемого потока, но возвращает Left<String, dynamic>не Right<dynamic, int>.

Самое простое решение - сообщить map назвать, какой тип возвращать:

  ...
    .map<Either<String, int>>( .... )

Тогда типы должны быть такими, как вы ожидаете (а не Either<dynamic, dynamic> как и в первом примере).

Я наконец-то понял, что происходит, погрузившись в виды дарца. Проблема в том, что компилятор не может определить тип Either в контекстах, где используется только Left или Right. Т.е. Left('') компилятор может вывести левую часть Either как строку, а в Right(5) он способен вывести правую часть Either как int. Однако он не способен понять другую часть соответственно. Использование приведенного ниже кода работает как с отступом.

Future<Either<String, int>> someWebCall() {
Future<int> response = Future.delayed(Duration(milliseconds: 200), () {
  throw SocketException('Well... ...it happens you know...');
});

return response.then((number) {
  return number > 50.0 ? Right(number) : Left('number is too small...');
}).catchError((error) {
  return Left<String, int>('are you already questioning the meaning of your life?');
});
Другие вопросы по тегам