能否不使用双层for循环遍历MySQL数据库中的多条记录?
如何避免使用双层for循环遍历MySQL数据库中的多条记录?
问题背景
我在用Rust的mysql crate查询数据库记录时,写了一段需要双层for循环的代码,想知道有没有办法简化掉内层循环。我的初始实现代码如下:
use mysql::*; use mysql::prelude::*; #[derive(Debug, PartialEq, Eq)] struct Persone { id: i32, email: String, } fn main() { let url = "mysql://root:9211@localhost:3306/test"; let pool = Pool::new(url).unwrap(); let mut conn = pool.get_conn().unwrap(); let select_all = conn.query_map( "SELECT id, email FROM persone", |(id, email)| { Persone { id, email } }, ); for row in select_all.iter() { for p in row { println!("{} - {}", p.id, p.email); } } }
解决方案
你已经找到了正确的简化方式,使用flatten()方法可以直接把嵌套的迭代器扁平化,从而去掉内层循环:
for row in select_all.iter().flatten() { println!("{} - {}", row.id, row.email); }
原理说明
这里的关键是理解select_all的类型:conn.query_map()返回的是Result<Vec<Persone>, mysql::Error>,所以当你调用iter()时,得到的是一个针对这个Result的迭代器(如果是Ok状态,迭代器里只有一个元素——整个Vec<Persone>)。这时候内层循环其实是在遍历这个Vec里的元素。
而flatten()方法会帮你处理两层迭代:它会先解开Result(忽略Err状态,如果你需要处理错误的话可以用flatten_err()或者先匹配Result),然后把Vec里的元素逐个迭代出来,这样你就能直接遍历到每一个Persone实例,不需要再套一层循环了。
如果需要处理查询可能出现的错误,更严谨的写法可以先匹配select_all的结果:
match select_all { Ok(people) => { for p in people { println!("{} - {}", p.id, p.email); } } Err(e) => eprintln!("查询出错: {}", e), }
这种写法也能避免双层循环,同时还能优雅处理错误情况。
内容的提问来源于stack exchange,提问作者matteo
相关产品推荐
相关产品推荐

