Dart/Flutter泛型报错:'(SearchFilterItemModel<DateTime>)=>String'不兼容dynamic
问题1:为何无法将dynamic类型适配为对应泛型类型?
Dart中函数类型的参数遵循逆变规则:若函数A能接收X类型参数,函数B能接收Y类型参数,只有当Y是X的父类时,B才能赋值给A的类型(因为B能处理更宽泛的输入)。
你的列表searchFilterItems声明为List<SearchFilterItemModel>,省略泛型参数后默认是List<SearchFilterItemModel<dynamic>>。此时每个filterItem的onPressed被推断为(SearchFilterItemModel<dynamic>) => String类型,但实际你传入的是(SearchFilterItemModel<DateTime>) => String和(SearchFilterItemModel<String>) => String。
这两个实际函数只能接收特定泛型参数的SearchFilterItemModel,而dynamic是所有类型的父类,SearchFilterItemModel<dynamic>是SearchFilterItemModel<DateTime>的父类。根据逆变规则,(SearchFilterItemModel<DateTime>) => String无法适配(SearchFilterItemModel<dynamic>) => String——因为前者只能处理更具体的子类实例,不能接收父类类型的参数,Dart的类型系统会阻止这种不安全的赋值。
问题2:如何修改代码解决该类型不匹配问题?
以下是几种可行的解决方案:
方案1:给泛型添加协变标记
如果onPressed逻辑不严格依赖T的特性,可以将SearchFilterItemModel的泛型标记为协变,允许子类泛型的函数参数适配父类类型:
typedef OnFilterButtonPressed<T> = String Function(SearchFilterItemModel<T> searchFilterItem); class SearchFilterItemModel<covariant T> { final String id, name; final OnFilterButtonPressed<T> onPressed; SearchFilterItemModel({ required this.id, required this.name, required this.onPressed, }); } List<SearchFilterItemModel> searchFilterItems = [ SearchFilterItemModel<DateTime>( id: "filter_id_date", name: "Date", onPressed: (item) => item.id, ), SearchFilterItemModel<String>( id: "filter_id_cost", name: "Cost", onPressed: (item) => item.id, ), ]; void main() { print(searchFilterItems.map<String>((filterItem) { return filterItem.onPressed(filterItem as SearchFilterItemModel<dynamic>); }).toList()); }
方案2:移除不必要的泛型依赖
如果你的onPressed逻辑(比如示例中仅返回id)不需要用到泛型参数T,可以直接简化定义:
typedef OnFilterButtonPressed = String Function(SearchFilterItemModel searchFilterItem); class SearchFilterItemModel { final String id, name; final OnFilterButtonPressed onPressed; SearchFilterItemModel({ required this.id, required this.name, required this.onPressed, }); } List<SearchFilterItemModel> searchFilterItems = [ SearchFilterItemModel( id: "filter_id_date", name: "Date", onPressed: (item) => item.id, ), SearchFilterItemModel( id: "filter_id_cost", name: "Cost", onPressed: (item) => item.id, ), ]; void main() { print(searchFilterItems.map<String>((filterItem) { return filterItem.onPressed(filterItem); }).toList()); }
这种方式最简洁,适合泛型T仅作为标记但未实际使用的场景。
方案3:显式类型转换(保留泛型)
如果需要保留泛型T的其他用途,可以手动处理类型转换:
typedef OnFilterButtonPressed<T> = String Function(SearchFilterItemModel<T> searchFilterItem); class SearchFilterItemModel<T> { final String id, name; final OnFilterButtonPressed<T> onPressed; SearchFilterItemModel({ required this.id, required this.name, required this.onPressed, }); } List<SearchFilterItemModel<Object>> searchFilterItems = [ SearchFilterItemModel<DateTime>( id: "filter_id_date", name: "Date", onPressed: (item) => item.id, ) as SearchFilterItemModel<Object>, SearchFilterItemModel<String>( id: "filter_id_cost", name: "Cost", onPressed: (item) => item.id, ) as SearchFilterItemModel<Object>, ]; void main() { print(searchFilterItems.map<String>((filterItem) { return (filterItem.onPressed as String Function(SearchFilterItemModel<Object>))(filterItem); }).toList()); }
注意:这种方式需要确保运行时类型匹配,避免类型转换错误。
内容的提问来源于stack exchange,提问作者Md. Ehsanul Hoque

