You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
  });
}

额外优化建议

  1. 移除多余的List.generate:原getItems里的List.generate(dbFilteredItems.length, (i) => dbFilteredItems[i])完全没必要,dbFilteredItems已经是List<IioMenuItem>类型,直接返回即可。
  2. 数据库层面过滤(性能更优):如果过滤条件可以转化为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:35:20