Dart中如何使用可变泛型?自定义OneOf类遇泛型数量限制
提问(翻译自英文)
我正在学习Dart和Flutter,了解过Either功能,但它需要使用Left和Right类,用法不够优雅。于是我自行实现了支持两个泛型参数的OneOf类,代码如下:
class OneOf<T1, T2> { T1? _result1; T2? _result2; OneOf.formResult(dynamic result) { if (result is T1) { _result1 = result; } else if (result is T2) { _result2 = result; } } handle( {required void Function(T1?) handleT1, required void Function(T2?) handleT2}) { if (_result1 != null) { handleT1(_result1); } else if (_result2 != null) { handleT2(_result2); } } }
该类可通过handle函数处理结果,现在我想扩展为支持三个泛型参数的版本,但Dart不允许同名类拥有不同数量的泛型参数(我有C#开发背景,C#支持此特性)。请问是否有办法实现可变数量的泛型参数,或是有其他我没注意到的解决方案?以下是该类的使用示例:
var message = "Hello world!!"; var result = OneOf<bool, String>.formResult(message); result.handle( handleT1: (boolResult) { print("I have received a boolean"); }, handleT2: (stringResult) { print("I have received the string '$message'"); }, );
回答
Dart确实不支持C#那样的泛型重载(同名类对应不同数量的泛型参数),但有几种可行方案实现多泛型的OneOf需求:
方案1:按泛型数量命名区分类
最直接的方式是给不同泛型数量的类加后缀,比如OneOf2、OneOf3,逻辑和你原有的OneOf一致,仅扩展参数数量:
// 双泛型版本 class OneOf2<T1, T2> { T1? _result1; T2? _result2; OneOf2.formResult(dynamic result) { if (result is T1) _result1 = result; else if (result is T2) _result2 = result; } handle({ required void Function(T1?) handleT1, required void Function(T2?) handleT2, }) { if (_result1 != null) handleT1(_result1); else if (_result2 != null) handleT2(_result2); } } // 三泛型版本 class OneOf3<T1, T2, T3> { T1? _result1; T2? _result2; T3? _result3; OneOf3.formResult(dynamic result) { if (result is T1) _result1 = result; else if (result is T2) _result2 = result; else if (result is T3) _result3 = result; } handle({ required void Function(T1?) handleT1, required void Function(T2?) handleT2, required void Function(T3?) handleT3, }) { if (_result1 != null) handleT1(_result1); else if (_result2 != null) handleT2(_result2); else if (_result3 != null) handleT3(_result3); } }
这种方式符合Dart语法规则,代码可读性强,使用时直接对应后缀即可。
方案2:借助freezed代码生成库(推荐)
如果不想手动维护重复的泛型判断逻辑,可以用freezed实现密封类(sum type),它能自动生成多类型分支的处理代码,支持任意数量的泛型参数:
- 添加依赖到
pubspec.yaml:
dependencies: freezed_annotation: ^2.4.1 dev_dependencies: build_runner: ^2.4.4 freezed: ^2.4.5
- 定义多类型结构:
import 'package:freezed_annotation/freezed_annotation.dart'; part 'one_of.freezed.dart'; @freezed class OneOf<T1, T2, T3> with _$OneOf<T1, T2, T3> { const factory OneOf.first(T1 value) = _First<T1, T2, T3>; const factory OneOf.second(T2 value) = _Second<T1, T2, T3>; const factory OneOf.third(T3 value) = _Third<T1, T2, T3>; }
- 运行代码生成命令:
flutter pub run build_runner build
- 使用时通过
when方法处理不同类型:
var result = OneOf<bool, String, int>.first(true); result.when( first: (bool val) => print("收到布尔值:$val"), second: (String val) => print("收到字符串:$val"), third: (int val) => print("收到整数:$val"), );
这种方式无需手动维护泛型字段和类型判断,扩展性更强,语法也更简洁。
补充说明
Dart目前没有可变数量的泛型参数(variadic generics),这是语言本身的限制。如果仅需少量泛型数量支持,方案1足够实用;如果需要频繁扩展或更优雅的语法,方案2的freezed是更优选择。
内容的提问来源于stack exchange,提问作者Bloodday
相关产品推荐
相关产品推荐

