Дротик: введите безопасность для функции, которая принимает функцию с переменным возвращаемым значением в качестве параметра - PullRequest
0 голосов
/ 30 октября 2018

Я пытаюсь создать функцию 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;
}

1 Ответ

0 голосов
/ 30 октября 2018

Вы можете абстрагироваться от типа возвращаемого значения, используя параметр типа:

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. Дротик ошибки не реализуют Exception, они реализуют Error. Exception - бессмысленный интерфейс маркера, используемый некоторыми брошенными объекты, которые пользователь должен отлавливать и обрабатывать , но в этом случае вы должны отлавливать конкретное исключение, например on FormatException, а не простое Exception. Итак, общее правило: никогда не писать on Exception).

...