rust - 使用`flat_map`为结构切片的字段创建迭代器
问题描述
给定结构的集合(向量/切片)。如何在每个结构中的某些字段上创建组合迭代器?
以下是使用的具体尝试flat_map
:
struct Game {
home_team: u8,
away_team: u8,
}
fn teams(games: &[Game]) -> impl Iterator<Item = u8> {
games
.iter()
.flat_map(|game| [game.home_team, game.away_team].iter().map(|x| x.clone()))
}
fn main() {
let data = &[
Game {
home_team: 1,
away_team: 2,
},
Game {
home_team: 1,
away_team: 3,
},
];
let non_unique_teams: Vec<u8> = teams(data).collect();
}
我的实际用例非常相似。特别是,构成迭代器基础的字段实现了Copy
,使克隆非常好。我的直觉告诉我这应该可行,因为我正在克隆我需要从传入切片中“获取”的唯一东西。显然,我对借用检查器的理解对我来说太差了。
解决方案
迭代器需要拥有包含结构字段副本的内存。在您的代码中,您创建一个本地数组并对其进行调用iter()
,这会导致对不拥有数据的切片引用进行迭代。
让迭代器拥有数据的最简单方法是为每个结构分配一个向量:
fn teams(games: &[Game]) -> impl Iterator<Item = u8> + '_ {
games
.iter()
.flat_map(|game| vec![game.home_team, game.away_team])
}
这将导致每次迭代中的堆分配。性能损失可能很小,因为分配器可能能够在每次迭代中重用分配。但是,如果您出于某种原因想要避免分配,您也可以使用Iterator::chain()
and的组合std::iter::once()
:
use std::iter::once;
fn teams(games: &[Game]) -> impl Iterator<Item = u8> + '_ {
games
.iter()
.flat_map(|game| once(game.home_team).chain(once(game.away_team)))
}
其他替代方案包括实现IntoIterator
和Clone
forGame
,这将允许您简单地使用crate或使用generatorsgames.iter().cloned().flatten()
,这是一个不稳定的功能,使实现这种迭代器更加方便。iter_vals
推荐阅读
- python - 有没有办法使用 itertuples 跳过第一个值?
- javascript - Multiple String Manipulation using js
- excel - 如何在excel中使用vba将不同的单元格值转换为单行?
- authentication - Getting a unique id after biometrics authentication in flutter
- javascript - Props updates in setInterval not reflected when changing component
- graphviz - 如何允许边与节点重叠?
- python - 使用 re 创建停用词列表
- go - 去 mod 供应商而不更新到最新版本
- .htaccess - http 用于本地,https 用于远程。怎么做?
- r - 将向量中的开始位置映射到另一个向量中的停止位置