Ошибка компилятора при использовании 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
Я действительно не могу обдумать это
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?');
});