【发布时间】:2021-03-14 10:54:53
【问题描述】:
我一直在使用 Rust 完成 2020 年 Advent of Code,试图产生涉及相当通用函数的解决方案,这些函数(理论上)可以在其他地方重用,而不必过多担心类型。对于第 2 天,问题涉及检查文件的每一行以确保它是符合某些给定条件的字符串。我目前的做法是定义一个类似于以下的函数:
fn filter_lines<'a>(lines: impl IntoIterator<Item = &'a str>) -> Vec<&'a str> {
lines
.into_iter()
.filter(|line| verify_line(line))
.collect()
}
这里,verify_line 只是一些函数,它接受 &str 并根据行是否符合特定规范生成布尔值。
问题是这个函数似乎必然会消耗迭代器。我尝试将其重写如下以使用对lines 的引用,并在对此进行操作之前克隆lines,但此代码无法编译:
fn filter_lines<'a>(lines: &impl IntoIterator<Item = &'a str>) -> Vec<&'a str> {
let lines = lines.clone();
lines
.into_iter()
.filter(|line| verify_line(line))
.collect()
}
编译器产生以下错误:
error[E0507]: cannot move out of `*lines` which is behind a shared reference
--> src/main.rs:40:5
|
40 | lines
| ^^^^^ move occurs because `*lines` has type `impl IntoIterator<Item = &'a str>`, which does not implement the `Copy` trait
我想我理解为什么不允许这样做,但我不确定如何惯用地定义一个不会消耗迭代器的函数,例如 filter_lines。那么,有什么更好的方法来实现这个filter_lines 函数,以便可以如下调用它?
let some_str: String = get_file_contents();
let lines = some_str.lines();
println!("Filtered lines: {:?}", filter_lines(&lines));
println!("All lines: {:?}", lines.collect::<Vec<&str>>());
【问题讨论】:
-
我应该澄清一下:我已经解决了 Advent of Code 中提出的问题,我并不是想“欺骗”解决它,我的问题只是为了我自己的利益 :)跨度>
-
请注意,
IntoIterator明确设计用于创建使用的迭代器。比较into_iter()和iter()方法,例如在 Vec 上。iter()不消耗输入,但实际上由通用切片类型定义。这是因为如果你不使用迭代器,你只是引用它,因此它需要一个所有者。