Dart:将具有不同返回值的函数作为参数的函数的类型安全

标签 dart parametric-polymorphism

我正在尝试创建一个 Dart 函数,该函数基本上用一些样板错误处理代码包装其他函数,否则返回原始函数返回的值。一个关键要求是它应该接受具有多种不同返回类型的函数,同时避免在多个不同函数之间重复常见的错误处理逻辑。我发现了一种似乎可以使用动态类型的方法,除了编译器无法检测到类型不匹配,因此它们仅在运行时被捕获。

有没有更好的方法来完成我在这里的目标,特别是在编译时捕获类型不匹配的方式?

下面是我的代码的简化示例,其中函数编译良好,但在运行时 getAString 会引发错误 Dart Error: Unhandled exception: type 'List<String>' is not a subtype of type 'String'
///API函数调用的签名
typedef APIFunctionCall = 动态函数();

dynamic doWithErrorHandling(APIFunctionCall fn, {retries: 2}) async {
  for (int attempts = 0; attempts < retries + 1; attempts++) {
    try {
      return await fn();
    }
    on Exception catch (e) {
      print(
          "This is just an example; actual function does a bunch of more specific error handling.");
    }
  }
}

Future<String> getAString() async {
  // Want a function that can support multiple return types but detect type errors
  String doesReturnAString =  await doWithErrorHandling(() async => 'hello world');  // This runs fine
  String doesntReturnAString = await doWithErrorHandling(() async => <String>['hello', 'world']);  // This throws an Error
  return doesntReturnAString;
}

最佳答案

您可以使用类型参数对返回类型进行抽象:

Future<T> doWithErrorHandling<T>(Future<T> fn(), {int retries = 2}) async {
  do {
    try {
      return await fn();
    } catch (e) {
      // record error.
    }
    retries--;
  } while (retries >= 0);
  return null;  // or whatever.
} 

有了它,您可以使用任何功能进行调用。在大多数情况下,类型参数可以从参数函数的静态类型中推断出来,或者从周围上下文所期望的类型中推断出来,但如果不是,您可以自己编写。
Future<String> getAString() async {
  String doesReturnAString =  await doWithErrorHandling(() async => 'hello world');  
  // The next line has a compile-time type error!
  String doesntReturnAString = await doWithErrorHandling(() async => <String>['hello', 'world']);
  return doesntReturnAString;
}

(作为一个不相关的提示,你永远不应该捕获 Exception 。Dart 错误不实现 Exception ,它们实现了 ErrorException 是一个无意义的标记接口(interface),由用户打算捕获的一些抛出对象使用句柄,但在这种情况下,您应该捕获特定异常,例如 on FormatException ,而不是普通的 Exception 。所以,一般规则:永远不要写 on Exception )。

关于Dart:将具有不同返回值的函数作为参数的函数的类型安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53056704/

相关文章:

haskell - 通用量化的意义

c++ - 多态和重载的区别

dart - result() 是 Dart 中的保留函数还是关键字?

dart - dart 聚合物中的条件 CSS

metaprogramming - 如何在Perl 6中将类设为参数化?

haskell - 为什么 `forall` 需要在数据定义中具有多态类型?

functional-programming - 简单类型的 lambda 演算与 Hindley-Milner 类型系统

dart - dart/flutter 中的这个一元后缀是什么?

string - 在Flutter Web中比较两个字符串/比较两个Cloud Firestore对象的documentID

dart - 随Dart 2安装的AngularDart