Dart泛型函数能否仅指定部分类型参数实现tryOrNull封装
问题描述
我尝试将「检测指定异常、若抛出该异常则返回null」的逻辑抽取为通用函数,初始实现代码如下:
T? tryOrNull<TException, T>(T Function() innerFunction) { try { return innerFunction(); } on TException { return null; } } // 用法示例 DateTime? parseDate(String date) { return tryOrNull<FormatException, DateTime>(() => DateTime.parse(date)); }
核心疑问
是否可以通过某种方式定义tryOrNull函数,无需手动指定第二个类型参数(即上述示例中的DateTime)?
我期望的调用形式如下,在我看来DateTime类型完全可以通过传入的innerFunction的返回值类型自动推断,无需手动声明:
// 期望用法 DateTime? parseDate(String date) { return tryOrNull2<FormatException>(() => DateTime.parse(date)); }
换言之,如何更优雅地指定需要捕获的异常类型?我希望实现类似Scala中Try(innerFunction).toOption的效果,但适配Dart的空安全特性(在我看来相比Option类型,Dart空安全使用起来更便捷)。
解决方案
Dart 截至3.x稳定版存在一个语言层面的限制:泛型函数调用时如果显式传入任意类型参数,就必须传入全部类型参数,不支持剩余参数自动推断,因此无法直接在原函数签名上实现你期望的单类型参数调用效果。
可以通过一个轻量的中间持有类拆分类型参数的指定时机,实现接近预期的调用效果,代码如下:
// 同步逻辑处理类 class _TryOrNullHandler<TException extends Object> { const _TryOrNullHandler(); T? call<T>(T Function() innerFunction) { try { return innerFunction(); } on TException { return null; } } } // 异步逻辑处理类 class _TryOrNullAsyncHandler<TException extends Object> { const _TryOrNullAsyncHandler(); Future<T?> call<T>(Future<T> Function() innerFunction) async { try { return await innerFunction(); } on TException { return null; } } } /// 捕获同步逻辑指定异常,异常时返回null final tryOrNull = <TException extends Object>() => _TryOrNullHandler<TException>(); /// 捕获异步逻辑指定异常,异常时返回null final tryOrNullAsync = <TException extends Object>() => _TryOrNullAsyncHandler<TException>();
调用方式
使用时只需要在指定异常类型后多写一对空括号,返回值类型会自动从传入的逻辑推断,无需手动声明:
DateTime? parseDate(String date) { // 自动推断返回值为DateTime?,无需手动指定第二个类型参数 return tryOrNull<FormatException>()(() => DateTime.parse(date)); } // 异步用法示例 Future<DateTime?> parseDateAsync(String date) async { return tryOrNullAsync<FormatException>()(() async { final res = await someAsyncParseOperation(date); return res; }); }
注:给
TException添加extends Object约束是为了符合Dart语法要求:on关键字后不允许跟随可空类型。
内容的提问来源于stack exchange,提问作者Joe M.
相关产品推荐
相关产品推荐

