Массивы в Rust
Массив (array) — это список значений одного типа фиксированного размера. Главное здесь — «фиксированного»: после создания массив не может ни вырасти, ни уменьшиться. Если нужно что-то, что меняет размер, для этого есть вектор.
Создаём массив
Заголовок раздела «Создаём массив»fn main() { let numbers: [i32; 5] = [1, 2, 3, 4, 5]; println!("{:?}", numbers);}Тип [i32; 5] читается как «массив из 5 значений i32». Длина — часть типа: [i32; 5] и [i32; 3] считаются разными типами.
Можно и просто перечислить значения, а тип Rust выведет сам:
let numbers = [1, 2, 3, 4, 5];Одно значение много раз
Заголовок раздела «Одно значение много раз»Чтобы заполнить массив одним и тем же значением N раз, есть сокращённая запись:
fn main() { let zeros = [0; 5]; // [0, 0, 0, 0, 0] println!("{:?}", zeros);}Доступ к элементам
Заголовок раздела «Доступ к элементам»К элементам массива обращаются по индексу в квадратных скобках, отсчёт начинается с 0:
fn main() { let fruits = ["яблоко", "банан", "вишня"];
println!("{}", fruits[0]); // яблоко println!("{}", fruits[2]); // вишня println!("Длина: {}", fruits.len());}Выход за границы не пройдёт незамеченным
Заголовок раздела «Выход за границы не пройдёт незамеченным»Если обратиться к несуществующему индексу, Rust остановит программу, а не станет молча читать мусор из памяти:
fn get_fruit(fruits: [&str; 3], index: usize) -> &str { fruits[index]}
fn main() { let fruits = ["яблоко", "банан", "вишня"]; println!("{}", get_fruit(fruits, 10)); // паника во время работы}thread 'main' (12345) panicked at src/main.rs:2:5:index out of bounds: the len is 3 but the index is 10Поток main запаниковал в строке 2: индекс вышел за границы — длина 3, а индекс 10.
Перебираем массив
Заголовок раздела «Перебираем массив»fn main() { let numbers = [10, 20, 30];
for n in numbers { println!("{n}"); }}Массивы массивов (двумерные массивы)
Заголовок раздела «Массивы массивов (двумерные массивы)»Массив может содержать другие массивы. Так получается сетка из строк и столбцов — как игровое поле или маленькая таблица. Тип grid ниже — [[i32; 3]; 2], то есть «2 строки, каждая — массив из 3 значений i32».
fn main() { // 2 строки, 3 столбца let grid = [ [1, 2, 3], [4, 5, 6], ];
println!("Строка 1, столбец 2: {}", grid[1][2]);
let mut total = 0; for row in grid { println!("{:?}", row); for value in row { total += value; } } println!("Сумма: {total}");}Вывод:
Строка 1, столбец 2: 6[1, 2, 3][4, 5, 6]Сумма: 21grid[1][2] значит «строка 1, а в ней столбец 2». Оба счёта начинаются с 0, так что это вторая строка, третье значение. Чтобы обойти все значения, нужен один цикл по строкам и второй, вложенный, — по значениям каждой строки.
Все строки должны быть одной длины, потому что длина строки — часть типа. Если при переборе нужна ещё и позиция, .iter().enumerate() даёт индекс и значение вместе. Это показано в уроке Цикл for.
Массивы или векторы
Заголовок раздела «Массивы или векторы»Используй массив, когда размер фиксирован и известен заранее (например, семь дней недели). Используй Vec, когда нужно добавлять или удалять элементы, — а на практике так бывает чаще всего. В повседневном коде на Rust массивы встречаются реже векторов.
Практика
Заголовок раздела «Практика»1. Сумма и среднее
Заголовок раздела «1. Сумма и среднее»Создай массив [4, 8, 15, 16, 23, 42]. Сложи все значения, а потом выведи сумму и среднее с двумя знаками после запятой. Подсказка: перебери массив через for, копи сумму в total, а перед делением преврати оба числа в f64 через as.
Показать решение
fn main() { let numbers = [4, 8, 15, 16, 23, 42];
let mut total = 0; for n in numbers { total += n; }
let average = total as f64 / numbers.len() as f64; println!("Сумма: {total}"); println!("Среднее: {average:.2}");}Вывод:
Сумма: 108Среднее: 18.00Без as f64 выражение total / numbers.len() было бы целочисленным делением, и вдобавок Rust пожаловался бы, что total (i32) и len() (usize) — разные типы.
2. Самый жаркий день
Заголовок раздела «2. Самый жаркий день»У тебя есть температуры за неделю: [18, 25, 12, 31, 22, 27, 19]. Найди и выведи самую высокую. Подсказка: начни с let mut hottest = temps[0];, затем перебирай и заменяй значение, как только найдёшь большее.
Показать решение
fn main() { let temps = [18, 25, 12, 31, 22, 27, 19];
let mut hottest = temps[0]; for t in temps { if t > hottest { hottest = t; } }
println!("Самый жаркий день: {hottest}");}Вывод:
Самый жаркий день: 31Важно начинать с temps[0], а не с 0: если бы все температуры были ниже нуля, старт с 0 дал бы неверный ответ.
- У массива фиксированная длина, и она — часть типа:
[i32; 5]. - К элементам обращаются через
массив[индекс], отсчёт с 0. - Выход за границы вызывает панику во время работы, а не неопределённое поведение.
- Массивы могут содержать массивы:
[[i32; 3]; 2]— это сетка, к которой обращаются какgrid[строка][столбец]. - Если размер нужно менять, используй
Vec.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Что верно о длине массива в Rust?
2. Что произойдёт при обращении к индексу за границами массива во время работы?
3. Что создаёт let zeros = [0; 5];?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- Массивы — книга «Язык программирования Rust»: официальное введение в массивы, в том числе почему длина — часть типа (перевод на русский).
- Массивы и срезы — Rust на примерах: короткие запускаемые примеры и первое знакомство со срезами (перевод на русский).
- Цикл по элементам коллекции с помощью for — книга «Язык программирования Rust»: почему цикл
forбезопаснее, чем обход массива по индексу (перевод на русский). array— документация стандартной библиотеки (на английском): что умеют массивы, напримерmapиas_slice, и как им достаются все методы срезов.