Rust: с нуля до своего органайзера Урок 23 из 35
Срезы: часть данных без копии
Урок 23. Передать функции часть числового набора, не создавая новый массив.
Текст переведён с помощью ИИ.
Предварительно: уроки 13, 15 и 20–22. Если границы 1..3 неясны, повторите урок 13.
Образ и опорная карта
Можно показать коллеге две соседние строки в своём списке, не переписывая весь лист. Срез (slice) — представление непрерывной части последовательности без владения её элементами. Образ ограничен: Rust связывает время использования среза с данными и проверяет границы; бумажный лист так себя не защищает.
Владелец → границы → срез для чтения → функция → владелец остаётся. &[u32] означает ссылку на последовательность чисел u32 с известной длиной, но не обещает конкретное число элементов. В отличие от [u32; 4] из урока 15, длина здесь не написана в типе. &minutes[1..3] берёт элементы с индексами 1 и 2: знак .. из урока 13 не включает правую границу. Обе границы должны быть допустимыми.
Считаем середину
В organizer сохраните старый src/main.rs отдельно, затем полностью замените его примером. В папке с Cargo.toml выполните cargo run. Другие файлы и зависимости не меняются. Предскажите результат; ниже нет сообщений Cargo.
До кода разберите новые места. middle ссылается только на два числа исходного массива. values: &[u32] позволяет sum принять такой срез. 0..values.len() создаёт индексы от нуля до длины, не включая длину; поэтому каждый values[index] допустим. u32 копируется как число, но сам массив ради вызова не копируется.
fn sum(values: &[u32]) -> u32 {
let mut total: u32 = 0;
for index in 0..values.len() {
total = total + values[index];
}
total
}
fn main() {
let minutes: [u32; 4] = [10, 20, 15, 5];
let middle = &minutes[1..3];
println!("Середина: {}", sum(middle));
println!("Первое: {}", minutes[0]);
}
Середина: 35
Первое: 10
middle охватывает 20 и 15. Он не может жить дольше minutes. Передача middle не отдаёт владение массивом, поэтому minutes[0] доступен после вызова. Для всего массива можно взять &minutes[0..minutes.len()]; функция не обязана знать длину заранее.
Граница и срок
Если правая граница больше длины, создание среза остановит программу с panic, как выход за границу массива в уроке 15. Для массива из четырёх элементов &minutes[4..4] — пустой допустимый срез, а &minutes[4..5] недопустим. Пустой срез можно передать sum: начальный ноль останется результатом.
Срез — ссылка, поэтому он не может пережить владельца. Следующая отдельная программа намеренно не компилируется с E0597:
fn main() {
let view: &[u32];
{
let values = [10, 20];
view = &values[0..2];
}
println!("{}", view[0]);
}
values заканчивается во внутреннем блоке, а view хотят использовать снаружи. Перенесите владельца во внешний блок или закончите использование среза внутри. Просто изменить имя среза недостаточно.
&str из урока 22 тоже является срезом, но текста. Для текстового среза границы задаются байтами и должны совпадать с границами символов UTF-8. Поэтому не переносите числовые индексы массива прямо на слово; подробности будут в уроке 25.
Проверка понимания
- Какие элементы даёт
&minutes[1..3]? - Почему
sumпринимает&[u32], а не[u32; 4]? - Можно ли использовать срез после исчезновения массива?
Проверьте: индексы 1 и 2; функция принимает срезы разных длин без копии массива; нет. Восстановите опорную карту.
Задание
Обязательное. С массивом [5, 10, 15, 20] вызовите свою sum(values: &[u32]) для первых двух и последних двух элементов. Выведите Первые: 15, Последние: 35, затем Всего элементов: 4 из исходного массива. Не создавайте ещё два массива и не вписывайте готовые суммы в вывод.
Граница. Проверьте пустой срез &minutes[0..0]: сумма должна быть нулём. Затем верните основное решение.
Подсказка
Используйте &minutes[0..2] и &minutes[2..4]; оба передайте одной функции. Внутри неё пройдите по 0..values.len().
Эталон после попытки
fn sum(values: &[u32]) -> u32 {
let mut total: u32 = 0;
for index in 0..values.len() {
total = total + values[index];
}
total
}
fn main() {
let minutes: [u32; 4] = [5, 10, 15, 20];
println!("Первые: {}", sum(&minutes[0..2]));
println!("Последние: {}", sum(&minutes[2..4]));
println!("Всего элементов: {}", minutes.len());
}
Первые: 15
Последние: 35
Всего элементов: 4
Одна функция работает с двумя частями массива; владелец остаётся доступен. Официальный разбор срезов.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.