0Pricing
Learn Rust Coding · Урок

Трейт Iterator

next и ленивые вычисления

«Трейт Iterator» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.

Что такое итератор

Итератор — это всё, что выдаёт последовательность значений по одному. В Rust итераторы — идиоматичный способ обрабатывать коллекции, такие как векторы, диапазоны и срезы.

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

Трейт Iterator

Трейт Iterator требует реализации одного метода — next — и одного ассоциированного типа — Item:

  • type Item — тип выдаваемого значения
  • fn next(&mut self) -> Option<Self::Item> — возвращает следующее значение

Пока остаются значения, он возвращает Some(value), а после завершения — None.

fn main() {
    let v = vec![10, 20, 30];
    let mut it = v.iter();
    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
}

next возвращает Option

Каждый вызов next продвигает итератор и передаёт Вам Option. Some оборачивает настоящее значение, а None обозначает конец.

Обратите внимание: next принимает &mut self — вызов изменяет внутреннее состояние, поэтому следующий вызов возвращает другое значение.

fn main() {
    let mut it = (1..4).into_iter();
    while let Some(n) = it.next() {
        println!("got {}", n);
    }
    println!("done");
}

Итераторы ленивы

Само создание итератора не делает ничего. Значения не вычисляются, пока кто-то не запросит их. Это называется ленивостью.

В следующем примере замыкание map не запускается, потому что мы не потребляем итератор.

fn main() {
    let nums = vec![1, 2, 3];
    let _doubled = nums.iter().map(|x| {
        println!("mapping {}", x);
        x * 2
    });
    println!("nothing printed above this line");
}

Потребление запускает работу

Чтобы ленивый итератор действительно начал работать, его нужно потребить. Цикл for — самый простой потребитель: он многократно вызывает next, пока не получит None.

Теперь то же замыкание map запускается для каждого элемента.

fn main() {
    let nums = vec![1, 2, 3];
    for x in nums.iter().map(|x| x * 2) {
        println!("value {}", x);
    }
}

Три способа выполнить итерацию

Коллекции предоставляют три метода, создающих итераторы:

  • iter() — выдаёт &T (заимствует)
  • iter_mut() — выдаёт &mut T (заимствует изменяемо)
  • into_iter() — выдаёт T (забирает владение)
fn main() {
    let mut v = vec![1, 2, 3];
    for x in v.iter_mut() {
        *x += 10;
    }
    println!("{:?}", v);
}

Циклы for используют into_iter

Когда Вы напрямую пишете for x in collection, Rust вызывает into_iter(), который потребляет коллекцию.

После этого цикла нельзя снова использовать v, потому что оно было перемещено в итератор.

fn main() {
    let v = vec![String::from("a"), String::from("b")];
    for s in v {
        println!("{}", s);
    }
    // v is no longer usable here
}

Диапазоны — это итераторы

Диапазон, например 0..5, сам является итератором и выдаёт 0, 1, 2, 3, 4. Конечное значение не включается. Для включительного диапазона используйте 0..=5.

Диапазоны отлично подходят для циклов со счётчиком без ручного отслеживания индекса.

fn main() {
    for i in 0..5 {
        print!("{} ", i);
    }
    println!();
    for i in 1..=3 {
        print!("{} ", i);
    }
    println!();
}

count: простой потребитель

count потребляет весь итератор и возвращает количество выданных им элементов. Это один из множества потребляющих адаптеров.

Поскольку он потребляет итератор, повторно использовать его нельзя.

fn main() {
    let total = (1..=100).count();
    println!("there are {} numbers", total);
}

sum: свёртка в одно значение

sum складывает все элементы и возвращает одно значение. Обычно Вы указываете целевой тип, чтобы Rust знал, результат какого типа нужно получить.

Это короче и понятнее, чем цикл с ручным накоплением.

fn main() {
    let total: i32 = (1..=5).sum();
    println!("sum is {}", total);
}

Зачем нужны итераторы

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

Освоение next, ленивости и потребления — основа всего дальнейшего материала.

Быстрая проверка

Проверьте, насколько хорошо Вы поняли трейт Iterator.

Повторение

Вы изучили основы итераторов Rust:

  • Трейту Iterator нужны только next и тип Item
  • next возвращает Some(value), а затем None
  • Итераторы ленивы — они ничего не делают, пока их не потребят
  • iter, iter_mut и into_iter управляют заимствованием и владением
  • Потребители, такие как for, count и sum, запускают обработку

Часто задаваемые вопросы

Урок «Трейт Iterator» бесплатный?

Да — полный текст урока «Трейт Iterator» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.

Чему я научусь в уроке «Трейт Iterator»?

next и ленивые вычисления Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Трейт Iterator»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Трейт Iterator
  2. map, filter, collect
  3. Адаптеры и потребители
  4. Пользовательские итераторы
← Назад к Learn Rust Coding