Что не так со следующим кодом Rust для печати каждого элемента массива?

Я новичок в Rest и изучаю его на «Rust Essential Training» на Linkedin Learning. В конце главы 5 (Программный поток и управление) я получил следующий вопрос в качестве викторины по главе.

Что не так со следующим кодом для печати каждого элемента my_array?

fn main() {
   let my_array = [1, 2, 3];

   for element in my_array {
       println!("element is {}", element);
   }
}

Я не мог придумать в этом ничего плохого, и когда я запустил его в визуальном коде, он заработал без проблем, но они сказали:

Цикл for не может перебирать my_array напрямую.

Эта программа должна использовать my_array.iter(), чтобы получить итератор по массиву.

Может ли кто-нибудь дать мне осмысленное объяснение? Я что-то упустил здесь?

Их пример устарел. В более новых версиях Rust массивы можно перебирать напрямую.

PitaJ 20.01.2023 19:55
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
4
1
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На последних версиях Rust (1.53 и выше) работает отлично . Вы можете убедиться сами на игровой площадке Rust.

До версии 1.53 это не работало, потому что массивы сами по себе не реализовывали IntoIterator. Начиная с Rust 1.53, что несколько сбивает с толку, все версии Rust фактически реализуют IntoIterator для массивов, но:

  1. Во всех выпусках потребляется прямая итерация (поскольку раньше это было незаконно, нет риска нарушения совместимости)
  2. В Rust 2021+ вызов .into_iter() для массива эквивалентен прямой итерации (она потребляет)
  3. В Rust 2015 и 2018 .into_iter() эквивалентно вызову .iter() (непотребляющая итерация по ссылке) или, точнее, array.into_iter() разрешается в (&array).into_iter(), а преобразование ссылки на массив в итератор делает непотребляющий итератор, поддерживаемый массивом.

Различие между редакциями связано с «небольшим хаком», который делает это так, хотя массивы реализуют IntoIterator во всех редакциях по состоянию на 1.53, в 2015 и 2018 годах, компилятор скрывает этот факт исключительно для случая .into_iter() синтаксиса вызова метода в массивах. , поэтому вместо этого он разрешается в (&array).into_iter() (что и произошло, когда массивы вообще не реализовывали IntoIterator). Это хак, потому что он защищает только от синтаксиса вызова метода; любые другие средства повторения массива (например, прямая итерация, iter.zip, прямой вызов IntoIterator::into_iter в массиве) найдут это IntoIterator и переберут его по (потреблению) значению, но ни один из этих методов не работал до 1.53 в любом случае, поэтому нет существующего кода полагался на них (компиляция array.into_iter() на Rust 2015 или 2018 выдаст громкое предупреждение о том, что значение меняется в Rust 2021).

До версии 1.53 вам нужно было явно преобразовывать в ссылку/срез массива (которые поддерживают итерацию) или явно вызывать .iter() или .into_iter() для массива (последний из которых по-прежнему не потребляет, разрешаясь в (&array).into_iter(); вот почему был необходим хак, поэтому новая функция не изменила поведение существующего кода для 2015 и 2018 годов).

Имейте в виду, что в этом конкретном случае элементы вашего массива реализуют Copy, поэтому содержимое массива не используется независимо от того, как оно повторяется; единственное различие заключается в том, перебираете ли вы ссылки на целые числа или на целые значения. Но для не-Copy типов важно различие между потреблением фактических значений и просто «просмотром» по ссылке.

Большое спасибо за ссылку и ваше объяснение.

Hanoch 20.01.2023 20:36

Я только что заметил, насколько фантастической является «Игровая площадка Rust». Я не могу отблагодарить вас за то, что вы включили это в свой ответ. Я буду часто использовать его для HIR, ASM и MIR. Еще раз спасибо.

Hanoch 20.01.2023 20:51

@Hanoch: Да, детская площадка довольно волшебная. Пожалуйста!

ShadowRanger 20.01.2023 20:59

Все ровно наоборот: начиная с версии Rust 1.53 этот код (прямая итерация) работает всегда. То, что меняется между редакциями, явно into_iter(): это эквивалентно прямой итерации в редакции 2021 и iter() в более старых редакциях с использованием вышеупомянутого хака.

Chayim Friedman 21.01.2023 19:39

@ChayimFriedman: Вы правы, я сначала неправильно прочитал (и теперь переписал).

ShadowRanger 21.01.2023 22:57

Это по-прежнему неверно: прямая итерация во всех редакциях потребляется с версии 1.53.0. Какие изменения into_iter(): это эквивалентно прямой итерации в редакции 2021 и iter() (не потребляющей) в предыдущих редакциях.

Chayim Friedman 22.01.2023 02:10

@ChayimFriedman: Хорошо, я перечитал ваши комментарии и объяснение, которое я давал несколько раз, и думаю, что теперь оно верно на 100%. Люди до версии 1.53 часто писали .into_iter() (хотя это ничего им не давало, кроме .iter()), и это работало (не потребляя много времени), потому что разрешалось (&array).into_iter(). Хак в 1.53 существует, чтобы избежать взлома кода до 1.53, заставляя Rust 2015 и 2018 продолжать обрабатывать этот код одинаково, даже несмотря на то, что массивы теперь реализуют IntoIterator. В Rust 2021 array.into_iter() разрешается непосредственно в массиве и потребляется. Спасибо за исправления!

ShadowRanger 25.01.2023 23:04

Да, не правильно.

Chayim Friedman 26.01.2023 04:56

Другие вопросы по теме