基于Freezed泛型字段过滤Artifact类列表的类型转换问题
解决Freezed泛型Artifact的类型推断与过滤问题
问题根源
核心问题是Dart泛型自动推断将Artifact实例的泛型参数定为Location而非具体的PointLocation/PolygonLocation。因为Location是Freezed联合类型,传入Location.fromPoint()时,Dart默认推断其类型为父类Location,最终生成的实例是_$NewArtifactImpl<Location>,而非期望的_$NewArtifactImpl<PointLocation>。
由于Dart泛型默认是不变的,Artifact<Location>并不是Artifact<PointLocation>的子类型,直接用as Artifact<PointLocation>强制转换会抛出类型不匹配错误。
解决方案
方案1:创建实例时显式指定泛型参数
这是最直接的解决方式,创建Artifact时手动指定泛型类型,确保实例泛型参数为具体的PointLocation或PolygonLocation:
// 创建Point类型Artifact时显式指定泛型 final pointArtifact = Artifact<PointLocation>.yourFactory( location: Location.fromPoint(...), ); // 创建Polygon类型Artifact同理 final polygonArtifact = Artifact<PolygonLocation>.yourFactory( location: Location.fromPolygon(...), );
生成的实例类型为_$NewArtifactImpl<PointLocation>,之后直接用whereType过滤即可:
List<Artifact<PointLocation>> get pointArtifacts => artifacts.whereType<Artifact<PointLocation>>().toList();
方案2:通过Freezed特性安全转换(适用于无法显式指定泛型的场景)
如果实例来自反序列化、第三方数据源等无法手动指定泛型的场景,可利用Freezed的联合类型能力添加安全转换逻辑:
首先在Artifact的Freezed定义中添加自定义方法:
@freezed class Artifact<T extends Location> with _$Artifact<T> { const factory Artifact.typeA({required T location}) = _TypeA<T>; const factory Artifact.typeB({required T location}) = _TypeB<T>; // 判断是否为Point类型的Artifact bool get isPoint => location is PointLocation; // 安全转换为Artifact<PointLocation>,失败则返回null Artifact<PointLocation>? get toPointArtifact { if (location is PointLocation) { // 重新构造泛型参数正确的实例 return when( typeA: (loc) => Artifact.typeA(location: loc as PointLocation), typeB: (loc) => Artifact.typeB(location: loc as PointLocation), ); } return null; } }
过滤时使用:
List<Artifact<PointLocation>> get pointArtifacts => artifacts .map((artifact) => artifact.toPointArtifact) .whereType<Artifact<PointLocation>>() .toList();
这种方式通过重新构造泛型参数正确的实例,避免了不安全的强制类型转换,同时保证类型安全。
内容的提问来源于stack exchange,提问作者Gabe
相关产品推荐
相关产品推荐

