为了测试目的,我试图抽象一个函数以同时接受std::str::Lines的实例和模拟版本,这个版本是由&str数组创建的。
我的代码(确实起作用)如下所示:
use std::fs;
#[test]
fn test_day_1() {
let v = ["3", "3", "4", "-2", "-4"].iter().map(|x| *x);
assert_eq!(day1(v), "334-2-4334-2-4");
}
fn day1_pre() -> String {
let contents = fs::read_to_string("day1.txt").expect("error reading file");
day1(contents.lines())
}
fn day1<'a>(lines: impl Iterator<Item = &'a str> + Clone) -> String {
lines
.map(|line| {
let v: Result<i32, _> = line.parse();
v.expect("could not parse line as integer")
})
.cycle()
.take(10)
.map(|x| x.to_string())
.collect()
}但是,这段代码的工作仅仅是因为测试中存在奇怪的.map(|x| *x)。如果删除它,将得到以下错误:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, &str> as Iterator>::Item == &str`
--> src/lib.rs:6:16
|
6 | assert_eq!(day1(v), "334-2-4334-2-4");
| ^^^^ expected `str`, found `&str`
...
14 | fn day1<'a>(lines: impl Iterator<Item = &'a str> + Clone) -> String {
| -------------- required by this bound in `day1`
|
= note: expected reference `&str`
found reference `&&str`我有点理解这个错误。iter返回一个&T,在本例中生成一个&&str。我不明白的是,为什么删除map并用into_iter (即let v = ["3", "3", "4", "-2", "-4"].into_iter();)替换iter也会出现同样的错误!
根据文献资料的说法,into_iter在T上迭代,因此它应该在这里工作吗?
在撰写这篇文章时,我还尝试用Vec替换数组并使用into_iter,这样最终的结果就是let v = vec!["3","3","4","-2","-4"].into_iter();,并且它工作了!然而,现在我更困惑了,为什么into_iter会为Vec而不是Array工作呢?
发布于 2021-09-06 15:08:13
这是与锈蚀1.53释放说明宣布的。数组的IntoIterator是在1.53中实现的新添加,但在2018年和2021年版本中的行为有所不同:
由于向后兼容性问题,这以前没有实现。因为
IntoIterator已经实现了对数组的引用,所以array.into_iter()已经在早期版本中编译,解析为(&array).into_iter()。在这个版本中,数组用一个小的变通方法来实现IntoIterator,以避免破坏代码。编译器将继续将(&array).into_iter(),解析为array.into_iter(),就好像特征实现不存在一样。这只适用于.into_iter()方法调用语法,不影响任何其他语法,如for e in [1, 2, 3]、iter.zip([1, 2, 3])或IntoIterator::into_iter([1, 2, 3]),它们都编译得很好。由于.into_iter()的这一特殊情况只是为了避免破坏现有代码,所以将在今年晚些时候发布的新版Rust 2021中删除它。有关更多信息,请参见版本公告。
因此,您的代码将编译得很好与锈蚀2021
发布于 2021-09-06 14:57:56
在这种情况下,您只需将任何可以作为引用的迭代器接受到str (任何&&&&&..&str都应该这样做):
fn day1<T>(lines: impl Iterator<Item = T> + Clone) -> String where T : AsRef<str>{
lines
.map(|line| {
let v: Result<i32, _> = line.as_ref().parse();
v.expect("could not parse line as integer")
})
.cycle()
.take(10)
.map(|x| x.to_string())
.collect()
}如果您在使用into_iter时读取当前警告,那么为什么Vec会工作而不是切片呢?
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> src/lib.rs:5:41
|
5 | let v = ["3", "3", "4", "-2", "-4"].into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= note: `#[warn(array_into_iter)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>跟随到问题链接,在那里有一个很好的解释。关键是:
[1, 2, 3].into_iter().for_each(|n| { *n; });当前起作用,因为into_iter返回对数组值的引用的迭代器,这意味着n确实是&{整数},并且可以取消引用。
https://stackoverflow.com/questions/69076428
复制相似问题