实现From<&Row>后无法直接collect为Vec<Pub>的疑问
问题:tokio-postgres查询结果直接collect为Vec失败的原因与解决办法
我用tokio-postgres查询伦敦酒吧位置数据,定义了Pub结构体及From<&Row>实现:
#[derive(Debug)] pub struct Pub { pub name: String, pub lon: f64, pub lat: f64, } impl From<&Row> for Pub { fn from(row: &Row) -> Self { let raw_name: String = row.get("name"); Pub { name: String::from(raw_name.trim()), lon: row.get("lon"), lat: row.get("lat"), } } }
尝试直接将查询结果的迭代器收集为Vec<Pub>时失败:
let data = client .query(&stmt, &[&user_pos.lon, &user_pos.lat, &DST_NEARBY]) .await .unwrap() .iter() // TODO: we could implement the trait `FromIterator<&tokio_postgres::Row>` for `Vec<Pub>` // .map(|row| Pub::from(row)) .collect::<Vec<Pub>>();
报错信息:
33 | .collect::<Vec<Pub>>(); | ^^^^^^^ value of type `Vec<Pub>` cannot be built from `std::iter::Iterator<Item=&tokio_postgres::Row>` | = help: the trait `FromIterator<&tokio_postgres::Row>` is not implemented for `Vec<Pub>` = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
原因解析
collect方法依赖FromIterator trait:Vec<T>默认只实现了FromIterator<T>,也就是只能从输出T类型的迭代器构建。而当前迭代器输出的是&Row类型,和目标类型Pub不匹配——Rust不会自动把From<&Row> for Pub的实现转换成FromIterator<&Row> for Vec<Pub>,两者是独立的trait,没有自动关联逻辑。
解决方案
不需要手动实现FromIterator<&Row> for Vec<Pub>,有更简洁的常规处理方式:
- 利用
Fromtrait自动生成的Into实现,用.map(Into::into)替代显式的Pub::from调用,代码更简洁:
let data = client .query(&stmt, &[&user_pos.lon, &user_pos.lat, &DST_NEARBY]) .await .unwrap() .iter() .map(Into::into) .collect::<Vec<Pub>>();
- 如果你偏好原写法,保留
.map(|row| Pub::from(row))也完全没问题,这是迭代器类型转换的标准写法,可读性清晰。
手动实现FromIterator并非不可行,但属于冗余操作——迭代器的map已经能完美完成类型转换,符合Rust的设计惯例,也避免了重复代码。
内容的提问来源于stack exchange,提问作者JPFrancoia
相关产品推荐
相关产品推荐

