Dart多泛型Result模式if语句类型判断问题求助
Dart/Flutter 双泛型Result密封类的类型推断问题解析
为什么switch能用,if却不行?
这本质是Dart编译器的类型推断规则差异导致的:
- 密封类的switch分支要求穷尽所有可能,编译器能完全确定每个分支对应的具体子类,哪怕你用
void忽略某个泛型参数,它也能精准匹配到SuccessResult或ErrorResult的具体实例,所以不用转换就能直接访问字段。 - 但if语句的类型推断保守得多,尤其是当Result带双泛型参数时,哪怕你用
is判断了类型,编译器没法确定这个SuccessResult的泛型参数具体是什么(比如你声明的是Result<void, MyError>,编译器没法自动把它和SuccessResult<void, MyError>划等号),所以不会自动提升类型,必须显式转换才能访问字段。
怎么解决?
1. 给泛型参数设默认值,减少冗余声明
给Result的两个泛型参数都设默认值void,这样使用时只需要指定你需要的那个泛型,编译器能更清晰地推断类型:
sealed class Result<S = void, E = void> {} class SuccessResult<S, E> extends Result<S, E> { final S result; SuccessResult(this.result); } class ErrorResult<S, E> extends Result<S, E> { final E error; ErrorResult(this.error); }
使用示例:
// 成功结果,只指定S泛型,E用默认void final success = SuccessResult<String>('加载完成'); // 错误结果,只指定E泛型,S用默认void final error = ErrorResult<Exception>(Exception('加载失败'));
2. if判断里显式类型转换
最简单直接的方式,在if判断后用as把Result转成具体子类,就能直接访问字段:
Result<String, Exception> result = SuccessResult('hello'); if (result is SuccessResult<String, Exception>) { print((result as SuccessResult<String, Exception>).result); }
3. 用扩展方法封装类型检查
给Result加个扩展方法,把类型检查和转换封装起来,代码更干净:
extension ResultHelper<S, E> on Result<S, E> { bool get isSuccess => this is SuccessResult<S, E>; bool get isError => this is ErrorResult<S, E>; SuccessResult<S, E>? get success => isSuccess ? this as SuccessResult<S, E> : null; ErrorResult<S, E>? get failure => isError ? this as ErrorResult<S, E> : null; }
使用示例:
final result = SuccessResult('test data'); if (result.isSuccess) { print(result.success?.result); }
4. Dart 3.0+用模式匹配(最推荐)
如果你的项目用Dart 3.0及以上版本,直接用模式匹配,编译器会自动推断类型,不用手动转换:
Result<String, Exception> result = SuccessResult('加载成功'); // 匹配成功结果,直接获取result字段 if (result case SuccessResult(:final result)) { print(result); } // 匹配错误结果,直接获取error字段 if (result case ErrorResult(:final error)) { print(error.toString()); }
内容的提问来源于stack exchange,提问作者asci
相关产品推荐
相关产品推荐

