與 Rust 編譯器的鬥爭 - 7

假設我們想在 Rust 中創建一個 slice 或 vector 的迭代器,迭代器從指定索引 k 處開始,而不是從起始索引 0 開始。這對於遍歷環形緩衝區非常有用。

你能實現下面的 iter_from() 函數,使程序精確地打印出 5,6,7,8,9,0,1,2,3,4 嗎?

fn iter_from<T>(slice: &[T], k: usize) -> impl Iterator<Item=&T> {
  // todo
}

fn main() {
  let array = [0,1,2,3,4,5,6,7,8,9];
  for i in iter_from(&array, 5) {
    print!("{},", i);
  } // 5,6,7,8,9,0,1,2,3,4,
}

我的解決方案是使用 Iterator::chain 方法:

fn iter_from<T>(slice: &[T], k: usize) -> impl Iterator<Item=&T> {
    slice[k..].iter().chain(slice[..k].iter())
}

現在,這是今天真正的挑戰——你能實現函數的可變變體嗎?

fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
  // todo
}

有人可能會認爲我們可以簡單地將 & 替換爲 & mut,將 iter 替換爲 iter_mut,就像這樣:

fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
  slice[k..].iter_mut().chain(slice[..k].iter_mut())
}

然而,這行不通。編譯器會報錯:對同一切片有多個可變借用。

error[E0499]: cannot borrow `*slice` as mutable more than once at a time
 --> src/main.rs:6:33
  || fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
  |                            - let's call the lifetime of this reference `'1`|     slice[k..].iter_mut().chain(slice[..k].iter_mut())
  |     ----------------------------^^^^^-----------------
  |     |                           |
  |     |                           second mutable borrow occurs here
  |     first mutable borrow occurs here
  |     returning this value requires that `*slice` is borrowed for `'1`

For more information about this error, try `rustc --explain E0499`.

這是因爲我們對同一個 slice 請求了兩次可變借用,一次是 slice[k..],另一次是 slice[..k]。我們知道這兩者是互斥的,但是編譯器還不夠聰明。

爲了顯式地告訴編譯器我們在索引 k 處將切片拆分爲兩個互斥的子切片,我們需要使用內置方法 split_at_mut(),它拆分切片併爲每一側返回可變借用:

pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T]&mut [T])

現在,我們可以實現 iter_mut_from() 方法:

fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
  let (s1, s2) = slice.split_at_mut(k);
  s2.iter_mut().chain(s1.iter_mut())
}

我們已經學習瞭如何在 Rust 中創建自定義迭代器,它從給定的索引開始並循環回到開頭。我們使用了 chain() 和 split_at_mut() 方法來實現這個功能。迭代器是在 Rust 中編寫優雅高效代碼的強大工具。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Xx2WuzOeVpTJTI5Q0Y1_NQ