Подтвердить что ты не робот

Как перебирать массив?

Я пытаюсь написать программу, которая включает в себя фильтрацию и складывание по массивам. Я использую Язык программирования ржавчины, первый вариант в качестве ссылки, но я не понимаю, что происходит, когда я формирую итераторы по массивам, Вот пример:

fn compiles() {
    let range = (1..6);
    let range_iter = range.into_iter();
    range_iter.filter(|&x| x == 2);
}

fn does_not_compile() {
    let array = [1, 4, 3, 2, 2];
    let array_iter = array.into_iter();
    //13:34 error: the trait `core::cmp::PartialEq<_>` is not implemented for the type `&_` [E0277]
    array_iter.filter(|&x| x == 2);
}

fn janky_workaround() {
    let array = [1, 4, 3, 2, 2];
    let array_iter = array.into_iter();
    // Note the dereference in the lambda body
    array_iter.filter(|&x| *x == 2);
}

(площадка для ржавчины)

В первой функции я следую за тем, что итератор по диапазону не переходит в собственность, поэтому я должен взять &x в filter лямбда, но я не понимаю, почему второй пример с массивом ведет себя по-разному.

4b9b3361

Ответ 1

В таких случаях очень полезно заставить компилятор рассказать вам тип переменной. Пусть запускается ошибка типа, назначая аргумент замыкания несовместимому типу:

array_iter.filter(|x| { let () = x; true });

Это не выполняется:

error[E0308]: mismatched types
  --> src/main.rs:12:33
   |
12 |     array_iter.filter(|x| { let () = x; true });
   |                                 ^^ expected &&{integer}, found ()
   |
   = note: expected type `&&{integer}`
              found type `()`

Теперь мы знаем, что тип x - это &&{integer} - ссылка на ссылку на какой-то целое число. Затем мы можем сопоставить это:

fn hooray() {
    let array = [1, 4, 3, 2, 2];
    let array_iter = array.into_iter();
    array_iter.filter(|&&x| x == 2);
}

Теперь вопрос становится "почему это ссылка на ссылку"? Краткая версия состоит в том, что итератор массива возвращает ссылки (см. Часть type Item = &'a T). Кроме того, Iterator::filter передает ссылку закрытию, чтобы предотвратить перемещение и впоследствии потерять не Copy.

Ответ 2

Массивы - это тип [T; N] в Rust, для любого типа элемента T и постоянное число N. Это массив фиксированного размера.

В настоящий момент Rust не реализует итераторы байтов для массивов. Из-за этого все массивы берутся за кусочки (тип [T]), и из этого массива доступны методы среза. Массивы также получают итератор среза, который называется std::slice::Iter<'a, T> и имеет элементы типа &'a T: он итерации по ссылке!

Вот почему into_iter() на a Range<i32> создает итератор i32 и into_iter() на [i32; 5] создает итератор &i32.

Если вам нужны итераторы значений для массивов, они реализованы в более широкой экосистеме, см. (1) и (2).

Ответ 3

Как сказал Shepmaster и bluss, вы можете проверить документацию для типа массива, в которой говорится:

Массивы с размерами от 0 до 32 (включительно) реализуют следующие если тип элемента позволяет это:

  • IntoIterator (реализовано для &[T; N] и &mut [T; N])

Как говорится, это только для ссылок и отражается в типе Item: type Item = &'a T и type Item = &'a mut T.