Dart中如何为异步getItems函数传递where子句?
Dart异步函数中自定义where过滤的问题解决
我有一个getItems异步函数,希望通过自定义where子句修改返回的列表,但因为异步特性报错。原函数的where逻辑是硬编码的,尝试封装新函数调用getItems时出现错误。
原函数代码
Future<List<IioMenuItem>> getItems() async { // ... final db = await openDatabase(path, readOnly: true); final List<Map<String, dynamic>> maps = await db.query('menu_items'); final dbFilteredItems = maps.map((item) => IioMenuItem( // assign values code removed )).where((element) { // <-- 希望这个where可以替换 if (filterState == FilterState.all) { return true; } else { return element.type.name == filterState.name; } }).toList(growable: false); return List.generate(dbFilteredItems.length, (i) { return dbFilteredItems[i]; }); }
失败的尝试代码
Future<List<IioMenuItem>> menuItems(FilterState filterState) async { final dbFilteredItems = getItems().where((element) { // 报错:The method 'where' isn't defined for the type 'Future'. if (filterState == FilterState.all) { return true; } else { return element.type.name == filterState.name; } }).toList(growable: false); return List.generate(dbFilteredItems.length, (i) { return dbFilteredItems[i]; }); }
报错信息
The method 'where' isn't defined for the type 'Future'.
错误原因
getItems()返回的是Future<List<IioMenuItem>>,这是一个异步任务对象,不是实际的列表。你不能直接对Future调用where,必须先通过await等待异步任务完成,拿到内部的List<IioMenuItem>后再执行过滤。
解决方案
方案1:先await获取列表再过滤
直接修改menuItems函数,先等待getItems返回实际列表,再执行where过滤:
Future<List<IioMenuItem>> menuItems(FilterState filterState) async { // 先通过await拿到实际的列表 final items = await getItems(); // 对列表执行where过滤 final filteredItems = items.where((element) { if (filterState == FilterState.all) { return true; } else { return element.type.name == filterState.name; } }).toList(growable: false); // 直接返回过滤后的列表,原代码的List.generate完全多余 return filteredItems; }
方案2:让getItems接收自定义过滤函数(更灵活)
如果希望getItems本身支持动态过滤,可以给它添加一个可选的过滤参数,这样后续可以传递任意过滤逻辑:
// 修改getItems,添加可选的过滤函数参数 Future<List<IioMenuItem>> getItems({bool Function(IioMenuItem)? filter}) async { final db = await openDatabase(path, readOnly: true); final List<Map<String, dynamic>> maps = await db.query('menu_items'); // 先把数据库数据转成IioMenuItem列表 final items = maps.map((item) => IioMenuItem( // 保留你的赋值逻辑 )).toList(growable: false); // 如果有传递过滤函数,就用它过滤;否则返回全部 if (filter != null) { return items.where(filter).toList(growable: false); } else { return items; } }
调用时直接传递过滤逻辑:
Future<List<IioMenuItem>> menuItems(FilterState filterState) async { return getItems(filter: (element) { if (filterState == FilterState.all) { return true; } else { return element.type.name == filterState.name; } }); }
额外优化建议
- 移除多余的List.generate:原
getItems里的List.generate(dbFilteredItems.length, (i) => dbFilteredItems[i])完全没必要,dbFilteredItems已经是List<IioMenuItem>类型,直接返回即可。 - 数据库层面过滤(性能更优):如果过滤条件可以转化为SQL查询,建议直接在
db.query阶段添加where条件,避免把所有数据从数据库读取到内存后再过滤,适合数据量大的场景:
Future<List<IioMenuItem>> getItems(FilterState filterState) async { final db = await openDatabase(path, readOnly: true); List<Map<String, dynamic>> maps; if (filterState == FilterState.all) { maps = await db.query('menu_items'); } else { // 直接在数据库层面过滤数据 maps = await db.query( 'menu_items', where: 'type = ?', whereArgs: [filterState.name], ); } return maps.map((item) => IioMenuItem( // 保留赋值逻辑 )).toList(growable: false); }
内容的提问来源于stack exchange,提问作者clever_trevor
相关产品推荐
相关产品推荐

