首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从&str数组中获取Iterator<Item=str>?

从&str数组中获取Iterator<Item=str>?
EN

Stack Overflow用户
提问于 2021-09-06 14:46:32
回答 2查看 306关注 0票数 2

为了测试目的,我试图抽象一个函数以同时接受std::str::Lines的实例和模拟版本,这个版本是由&str数组创建的。

我的代码(确实起作用)如下所示:

代码语言:javascript
复制
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)。如果删除它,将得到以下错误:

代码语言:javascript
复制
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_iterT上迭代,因此它应该在这里工作吗?

在撰写这篇文章时,我还尝试用Vec替换数组并使用into_iter,这样最终的结果就是let v = vec!["3","3","4","-2","-4"].into_iter();,并且它工作了!然而,现在我更困惑了,为什么into_iter会为Vec而不是Array工作呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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

票数 4
EN

Stack Overflow用户

发布于 2021-09-06 14:57:56

在这种情况下,您只需将任何可以作为引用的迭代器接受到str (任何&&&&&..&str都应该这样做):

代码语言:javascript
复制
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会工作而不是切片呢?

代码语言:javascript
复制
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确实是&{整数},并且可以取消引用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69076428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档