dart Linter告诉我强制转换是不必要的,但是没有它会崩溃

k4aesqcs  于 2023-04-03  发布在  其他
关注(0)|答案(2)|浏览(115)

我遇到了一个我无法解决的行为。基本上,我试图获取数据,并返回这些数据的Future,其中一些请求可能会失败,但我们可以忽略它们。
这是我到目前为止的想法:对于我们想要获取的每个数据,创建一个future,如果失败则返回null,否则返回值。然后等待所有future,并删除null值。
下面是我的代码:(简单测试数据)

Future<List<String>> testFunc() {
  // create a result list
  List<Future<String?>> result = List.empty(growable: true);

  // put 10 future in the results
  for(int i = 0; i < 10; i++) {
    result.add(
      // create a future that may fail
      Future.delayed(Duration(seconds: i), () {
        if(i % 2 == 0) { return i; }
        else { throw Error(); }
      })
      // if the future succeed, return the value
      .then((value) {
        return "got from future : $value";
      })
      // otherwise, returns "null" as we are expecting a future returning a nullable value
      .catchError((error) {
        return null; // <========= Linter error here
      })
    );
  }

  // then, wait for all futures, and remove the ones that crashed
  return Future.wait(result).then((listOfNullable) => listOfNullable.where((element) => element != null).map((e) => e!).toList());
}

当我运行这个函数时,其中一个future失败并返回null,我遇到了一个错误:The error handler of Future.catchError must return a value of the future's type,我不明白,因为null是String?的有效值?
有一种方法是显式强制转换:

Future<List<String>> testFunc() {
// create a result list
List<Future<String?>> result = List.empty(growable: true);

// put 10 future in the results
for(int i = 0; i < 10; i++) {
 result.add(
   // create a future that may fail
   Future.delayed(Duration(seconds: i), () {
     if(i % 2 == 0) { return i; }
     else { throw Error(); }
   })
   // if the future succeed, return the value
   .then((value) {
     return "got from future : $value" as String?; // <========= Linter error here
   })
   // otherwise, returns "null" as we are expecting a future returning a nullable value
   .catchError((error) {
     return null as String?; // <========= Linter error here
   })
 );
}

// then, wait for all futures, and remove the ones that crashed
return Future.wait(result).then((listOfNullable) => listOfNullable.where((element) => element != null).map((e) => e!).toList());
}

但是现在,linter告诉我我有一个不必要的造型,我正在尝试删除任何linter错误。
我错过了什么?

hi3rlvi2

hi3rlvi21#

linter错误是由对then(...)的调用引起的,dart linter急切地将其解析为then<String>而不是then<String?>
您可以显式指定类型以解决此行为:

Future<List<String>> testFunc() {
  List<Future<String?>> result = List.empty(growable: true);

  for(int i = 0; i < 10; i++) {
    result.add(
      Future.delayed(Duration(seconds: i), () {
        if(i % 2 == 0) { return i; }
        else { throw Error(); }
      })
      .then<String?>((value) { // <- Change here!
        return "got from future : $value";
      })
      .catchError((error) {
        return null; // No more linter warning
      })
    );
  }

  // then, wait for all futures, and remove the ones that crashed
  return Future.wait(result).then((listOfNullable) => listOfNullable.where((element) => element != null).map((e) => e!).toList());
}
bq9c1y66

bq9c1y662#

也就是说,提供给Future<T>.catchError的回调必须返回TFuture<T>(也称为FutureOr<T>)。
由于您在Future.then<R>返回的Future<R>上调用catchError,因此错误回调必须返回FutureOr<R>。您需要:

.then((value) {
    return "got from future : $value"; 
  })

由于没有为Future.then<R>提供显式类型,R是从callback的返回类型(不可为空的String. As jraufeisen explained)中推断出来的,因此可以通过显式指定R(而不是允许它被推断出来)来修复此问题。
或者,我强烈建议使用async-awaittry-catch,而不是使用Future.thenFuture.catchError。这样做可以避免这些问题(或者至少使它们更容易推理)。在您的情况下,helper函数会使转换更容易:

Future<List<String>> testFunc() {
  // create a result list
  List<Future<String?>> result = List.empty(growable: true);

  Future<String?> helper(int i) async {
    try {
      // create a future that may fail
      var value = await Future.delayed(Duration(seconds: i), () {
        if (i % 2 == 0) {
          return i;
        } else {
          throw Error();
        }
      });
      // if the future succeed, return the value
      return "got from future : $value";
    } on Error {
      // otherwise, returns "null" as we are expecting a future returning a nullable value
      return null;
    }
  }

  // put 10 future in the results
  for (int i = 0; i < 10; i++) {
    result.add(helper(i));
  }

  // then, wait for all futures, and remove the ones that crashed
  return Future.wait(result).then((listOfNullable) => listOfNullable
      .where((element) => element != null)
      .map((e) => e!)
      .toList());
}

使用.map代替.where来过滤掉null s,使用collection-for来避免创建一个空的List并使其增长,并删除剩余的Future.then

Future<List<String>> testFunc() async {
  Future<String?> helper(int i) async {
    try {
      // create a future that may fail
      var value = await Future.delayed(Duration(seconds: i), () {
        if (i % 2 == 0) {
          return i;
        } else {
          throw Error();
        }
      });
      // if the future succeed, return the value
      return "got from future : $value";
    } on Error {
      // otherwise, returns "null" as we are expecting a future returning a nullable value
      return null;
    }
  }

  // then, wait for all futures, and remove the ones that crashed
  var result = await Future.wait([
    for (var i = 0; i < 10; i++) helper(i),
  ]);
  return result.whereType<String>().toList();
}

相关问题