Rust中collect指定Vec<&str>报错及迭代器类型疑问解析
先看你给出的两段代码:
正常运行的代码:
fn main() { let v1 = vec!["lemonade", "lemon", "type", "lid"]; println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).collect::<Vec<_>>()); }
报错的代码:
fn main() { let v1 = vec!["lemonade", "lemon", "type", "lid"]; println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).collect::<Vec<&str>>()); }
核心问题:迭代器的元素类型不匹配
先搞清楚迭代器返回的具体类型
v1 是 Vec<&str> 类型,调用 iter() 方法时,它会返回一个遍历容器元素引用的迭代器——也就是说,这个迭代器的每个元素是原容器元素的引用。原容器的元素是 &str,所以迭代器的元素类型是 &&str(对字符串切片的引用)。
当你用 collect::<Vec<_>>() 时,Rust编译器会自动推导类型:它知道迭代器的元素是 &&str,所以会把 Vec<_> 推导成 Vec<&&str>,因此能正常编译运行。
而当你强制指定 collect::<Vec<&str>>() 时,就出现了类型不匹配:你要求把 &&str 类型的元素收集成 Vec<&str>,但Rust找不到对应的转换逻辑。
拆解编译器错误提示
报错信息里的关键内容:
error[E0277]: a value of type
Vec<&str>cannot be built from an iterator over elements of type&&str
这句话直接点出问题:你要构建的是 Vec<&str>,但迭代器给出的元素是 &&str,两者类型不兼容。
下面的帮助信息进一步解释:
= help: the trait
FromIterator<&&str>is not implemented forVec<&str>
= help: the traitFromIterator<T>is implemented forVec<T>
collect 方法的底层依赖 FromIterator trait:Vec<T> 只实现了 FromIterator<T>——也就是说,只有当迭代器的元素类型是 T 时,才能收集成 Vec<T>。这里你要的 Vec<&str> 只接受元素类型为 &str 的迭代器,而你的迭代器元素是 &&str,所以不满足约束,报错。
最后的note部分是在提示 collect 方法的定义约束:
note: required by a bound in
collect
--> ...
1788 | fn collect<B: FromIteratorSelf::Item>(self) -> B
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound incollect
意思是 collect 要求目标类型 B 必须实现 FromIterator<Self::Item>,其中 Self::Item 就是迭代器的元素类型(这里是 &&str),而 Vec<&str> 没实现 FromIterator<&&str>,所以不符合要求。
两种修复方法
方法1:用into_iter()代替iter()
into_iter() 会获取容器的所有权,直接遍历容器的元素本身(而不是元素的引用)。对于 Vec<&str> 来说,into_iter() 返回的迭代器元素类型是 &str,这样就能直接收集成 Vec<&str>:
fn main() { let v1 = vec!["lemonade", "lemon", "type", "lid"]; println!("{:?}", v1.into_iter().filter(|item| item.starts_with("l")).collect::<Vec<&str>>()); }
方法2:解引用迭代器元素
在 filter 之后用 map 把 &&str 解引用成 &str,这样迭代器元素类型就变成了 &str,就能收集成 Vec<&str>:
fn main() { let v1 = vec!["lemonade", "lemon", "type", "lid"]; println!("{:?}", v1.iter().filter(|item| item.starts_with("l")).map(|s| *s).collect::<Vec<&str>>()); }
内容的提问来源于stack exchange,提问作者constperson

