簡體   English   中英

獲取迭代器<item=str>來自 &str?</item=str>

[英]Getting an Iterator<Item=str> from an array of &str?

我正在嘗試抽象一個 function 以獲取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並將iter替換為into_iter (即let v = ["3", "3", "4", "-2", "-4"].into_iter(); )也因同樣的錯誤而失敗!

根據文檔into_iter迭代T ,因此它應該在這里工作?

在寫這篇文章時,我還嘗試用Vec替換數組並使用into_iter ,這樣最終的結果是let v = vec,["3","3","4","-2"."-4"];into_iter(); 它奏效了,但是,現在我更加困惑了,為什么into_iterVec有效但對Array無效?

這是在Rust 1.53 發行說明中公布的。 IntoIterator for arrays 是在 1.53 中實現的新增功能,但在 2018 和 2021 版本中表現不同:

由於向后兼容性問題,這在以前沒有實現。 因為IntoIterator已經實現了對 arrays 的引用,所以array.into_iter()已經在早期版本中編譯,解析為(&array).into_iter()

截至此版本,arrays 實施 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 中將其刪除。 有關詳細信息,請參閱版本公告。

因此,您的代碼將在 Rust 2021 下正常編譯

在這種情況下,您可以將任何可以作為引用的內容的迭代器帶入 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_iterVec而不是切片起作用,好吧,如果您在使用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>

按照有很好解釋的問題鏈接進行操作。 要點是:

[1, 2, 3].into_iter().for_each(|n| { *n; }); 目前這是可行的,因為 into_iter 返回對數組值的引用的迭代器,這意味着 n 確實是 &{integer} 並且可以取消引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM