Введение
В этом лабе мы изучим массивы и срезы в Rust. Массив — это коллекция объектов одного типа, хранящихся в последовательных ячейках памяти, и его длина известна на этапе компиляции. Срез, напротив, похож на массив, но его длина неизвестна на этапе компиляции. Срезы можно использовать для взятия части массива. Также рассмотрим, как создавать массивы, получать доступ к элементам, вычислять длину, выделять память, брать массивы в качестве срезов и работать с пустыми срезами. Кроме того, обсудим, как безопасно получать доступ к элементам массива с помощью метода .get() и обрабатывать ошибки выхода за границы.
Примечание: Если в лабе не указано имя файла, вы можете использовать любое имя, которое хотите. Например, вы можете использовать
main.rs, скомпилировать и запустить его с помощьюrustc main.rs &&./main.
Массивы и срезы
Массив — это коллекция объектов одного типа T, хранящихся в последовательных ячейках памяти. Массивы создаются с использованием квадратных скобок [], и их длина, которая известна на этапе компиляции, является частью их сигнатуры типа [T; length].
Срезы похожи на массивы, но их длина неизвестна на этапе компиляции. Вместо этого срез представляет собой двухсловный объект: первое слово — это указатель на данные, второе слово — длина среза. Размер слова совпадает с размером usize, определяемым архитектурой процессора, например, 64 бита на x86-64. Срезы можно использовать для взятия части массива и имеют сигнатуру типа &[T].
use std::mem;
// Эта функция берет срез в качестве аргумента.
fn analyze_slice(slice: &[i32]) {
println!("Первый элемент среза: {}", slice[0]);
println!("Срез содержит {} элементов", slice.len());
}
fn main() {
// Массив фиксированного размера (сигнатура типа избыточна).
let xs: [i32; 5] = [1, 2, 3, 4, 5];
// Все элементы можно инициализировать одним и тем же значением.
let ys: [i32; 500] = [0; 500];
// Индексация начинается с 0.
println!("Первый элемент массива: {}", xs[0]);
println!("Второй элемент массива: {}", xs[1]);
// `len` возвращает количество элементов в массиве.
println!("Количество элементов в массиве: {}", xs.len());
// Массивы хранятся на стеке.
println!("Массив занимает {} байт", mem::size_of_val(&xs));
// Массивы можно автоматически взять в качестве срезов.
println!("Взять весь массив в качестве среза.");
analyze_slice(&xs);
// Срезы могут указывать на часть массива.
// Они имеют форму [starting_index..ending_index].
// `starting_index` — это первый элемент среза.
// `ending_index` на единицу больше последнего элемента среза.
println!("Взять часть массива в качестве среза.");
analyze_slice(&ys[1.. 4]);
// Пример пустого среза `&[]`:
let empty_array: [u32; 0] = [];
assert_eq!(&empty_array, &[]);
assert_eq!(&empty_array, &[][..]); // То же, но более подробно
// Элементы массива можно безопасно получить с помощью `.get`,
// который возвращает `Option`. Это можно обработать, как показано ниже,
// или использовать с `.expect()`, если вы хотите, чтобы программа завершилась
// с красивым сообщением вместо того, чтобы просто продолжать работу.
for i in 0..xs.len() + 1 { // Упс, на один элемент дальше!
match xs.get(i) {
Some(xval) => println!("{}: {}", i, xval),
None => println!("Замедлите! {} слишком далеко!", i),
}
}
// Доступ за границы массива вызывает ошибку компиляции.
//println!("{}", xs[5]);
// Доступ за границы среза вызывает ошибку времени выполнения.
//println!("{}", xs[..][5]);
}
Резюме
Поздравляем! Вы завершили лабу по Массивам и Срезам. Вы можете практиковаться в других лабах в LabEx, чтобы улучшить свои навыки.