Dart增强枚举报错:非重定向const工厂调用非常量表达式
错误根本原因
你当前代码里的Option(...)实例初始化不属于合法的编译时常量表达式,这就是编译报错的直接原因。
编译错误核心提示:
Non-redirecting const factory invocation is not a constant expression.
Dart 增强枚举的语法要求:所有枚举实例声明时传入的构造参数,必须是可在编译阶段完全求值的常量表达式——因为枚举值本身是编译期常量。
你使用的Option是Freezed代码生成的类,你在枚举值里调用的Option(name: 'xxx', ...)本质是调用它的const factory非重定向工厂构造函数。Dart语言规范明确规定:非重定向类型的const工厂构造函数调用,不属于合法的常量表达式。哪怕你显式加了const修饰,编译器也无法在编译阶段直接解析这类工厂的返回值,因此直接抛出上述错误。
另外你当前的枚举实现还有冗余问题:你既为枚举定义了final Option value常量字段,又额外维护了一份静态items映射存储重复的Option实例,不仅多余,还可能出现两边值不一致的隐患。
可直接使用的修复方案
方案1(最简便,无需修改Option类)
Freezed为你生成的私有实现类_Option自带普通const构造函数,同包内可以直接访问,你只需要把枚举值里的Option(...)替换为_Option(...),同时删除冗余的静态items映射,直接基于枚举自带的value字段实现存量代码依赖的getter和方法即可:
// 确保已正确导入option.dart,同包下可直接访问生成的_Option类 enum VgnItmType { nullObject(value: _Option(name: 'Null Object', iconCodePoint: 0xf07a, id: 0)), groceryItm(value: _Option(name: 'Grocery Item', iconCodePoint: 0xf291, id: 1)), menuItm(value: _Option(name: 'Menu Item', iconCodePoint: 0xf2e3, id: 2)), groceryStoreItm( value: _Option(name: 'Grocery Store', iconCodePoint: 0xf07a, id: 3)), restaurantItm( value: _Option(name: 'Restaurant', iconCodePoint: 0xf2e7, id: 4)), eventItm(value: _Option(name: 'Event', iconCodePoint: 0xf500, id: 5)), fashionItm(value: _Option(name: 'Fashion Item', iconCodePoint: 0xf553, id: 6)), recipeItm(value: _Option(name: 'Recipe', iconCodePoint: 0xf86b, id: 7)); const VgnItmType({required this.value}); final Option value; // 直接复用value字段,兼容存量代码调用 String get name => value.name; int get id => value.id; int get iconCodePoint => value.iconCodePoint; Option get option => value; static List<Option> get options => values.map((e) => e.value).toList()..sort((a, b) => a.name.compareTo(b.name)); static List<VgnItmType> get enums => values.toList()..sort((a, b) => a.name.compareTo(b.name)); static VgnItmType idToEnum(int id) => values.firstWhere((element) => element.id == id); }
注意:修改完成后需要重新执行
dart run build_runner build确保Freezed代码生成是最新状态。
方案2(不引用私有类,修改Option类)
如果你不想直接依赖Freezed生成的私有类,可以给Option添加一个const普通构造函数,枚举值里调用这个公开的const构造即可:
@freezed class Option extends Entity with _$Option { const factory Option( {required int iconCodePoint, String? fontFamily, required int id, required String name}) = _Option; // 新增公开const构造 const Option.publicConst({ required this.iconCodePoint, this.fontFamily, required this.id, required this.name, }); const Option._(); factory Option.empty() { return const Option(iconCodePoint: 0, id: 0, name: ''); } factory Option.fromJson(Map<String, dynamic> json) => _$OptionFromJson(json); }
之后枚举值里把Option(...)替换为Option.publicConst(...)即可,其余逻辑和方案1一致。
内容的提问来源于stack exchange,提问作者BeniaminoBaggins

