从 &str 数组中获取 Iterator<Item=str>?
Getting an Iterator<Item=str> from an array of &str?
我正在尝试抽象一个函数以获取 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
returns 一个 &T
,在这种情况下会产生一个 &&str
。我不明白的是为什么删除 map
并将 iter
替换为 into_iter
(即 let v = ["3", "3", "4", "-2", "-4"].into_iter();
)也会失败并出现相同的错误!
根据 the documentation,into_iter
迭代 T
,因此它应该在这里工作?
在编写此 post 时,我还尝试用 Vec
替换数组并使用 into_iter
,这样最终结果是 let v = vec!["3","3","4","-2","-4"].into_iter();
并且成功了!但是,现在我更加困惑了,为什么 into_iter
对 Vec
有效,但对 Array
无效?
在这种情况下,您可以将任何可以作为引用的内容的迭代器带入 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
而不是切片,好吧,如果您在使用 into_iter
时阅读当前警告:
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>
关注issue link 那里有很好的解释。
重点是:
[1, 2, 3].into_iter().for_each(|n| { *n; });
Currently this works,
as into_iter returns an iterator over references to the array's
values, meaning that n is indeed &{integer} and can be dereferenced.
这是在 Rust 1.53 release notes 中宣布的。 IntoIterator
for arrays 是在 1.53 中实现的新增功能,但在 2018 和 2021 版本中表现不同:
This was not implemented before, due to backwards compatibility problems. Because IntoIterator
was already implemented for references to arrays, array.into_iter()
already compiled in earlier versions, resolving to (&array).into_iter()
.
As of this release, arrays implement IntoIterator with a small workaround to avoid breaking code. The compiler will continue to resolve array.into_iter()
to (&array).into_iter()
, as if the trait implementation does not exist. This only applies to the .into_iter()
method call syntax, and does not affect any other syntax such as for e in [1, 2, 3]
, iter.zip([1, 2, 3])
or IntoIterator::into_iter([1, 2, 3])
, which all compile fine.
Since this special case for .into_iter()
is only required to avoid breaking existing code, it is removed in the new edition, Rust 2021, which will be released later this year. See the edition announcement for more information.
因此您的代码将 compile just fine 与 Rust 2021
我正在尝试抽象一个函数以获取 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
returns 一个 &T
,在这种情况下会产生一个 &&str
。我不明白的是为什么删除 map
并将 iter
替换为 into_iter
(即 let v = ["3", "3", "4", "-2", "-4"].into_iter();
)也会失败并出现相同的错误!
根据 the documentation,into_iter
迭代 T
,因此它应该在这里工作?
在编写此 post 时,我还尝试用 Vec
替换数组并使用 into_iter
,这样最终结果是 let v = vec!["3","3","4","-2","-4"].into_iter();
并且成功了!但是,现在我更加困惑了,为什么 into_iter
对 Vec
有效,但对 Array
无效?
在这种情况下,您可以将任何可以作为引用的内容的迭代器带入 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
而不是切片,好吧,如果您在使用 into_iter
时阅读当前警告:
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>
关注issue link 那里有很好的解释。 重点是:
[1, 2, 3].into_iter().for_each(|n| { *n; });
Currently this works, as into_iter returns an iterator over references to the array's values, meaning that n is indeed &{integer} and can be dereferenced.
这是在 Rust 1.53 release notes 中宣布的。 IntoIterator
for arrays 是在 1.53 中实现的新增功能,但在 2018 和 2021 版本中表现不同:
This was not implemented before, due to backwards compatibility problems. Because
IntoIterator
was already implemented for references to arrays,array.into_iter()
already compiled in earlier versions, resolving to(&array).into_iter()
.
As of this release, arrays implement IntoIterator with a small workaround to avoid breaking code. The compiler will continue to resolve
array.into_iter()
to(&array).into_iter()
, as if the trait implementation does not exist. This only applies to the.into_iter()
method call syntax, and does not affect any other syntax such asfor e in [1, 2, 3]
,iter.zip([1, 2, 3])
orIntoIterator::into_iter([1, 2, 3])
, which all compile fine.
Since this special case for
.into_iter()
is only required to avoid breaking existing code, it is removed in the new edition, Rust 2021, which will be released later this year. See the edition announcement for more information.
因此您的代码将 compile just fine 与 Rust 2021