Pattern matching: срезы
Восполняя пробелы в изменениях Rust, которые происходили за время моего небольшого отсутствия, в одном из репортов заметил интересную вещь: стабилизацию #![feature(slice_patterns)]
(Issue #320). Хотя образцы срезов были в языке уже довольно давно, но до этого моменты они были довольно ограничены. slice_patterns
впервые появились еще в версии 1.26, и предоставили значительные улучшения, в частности стало удобнее работать с массивами переменной длины. Ниже разберем несколько примеров, которые теперь доступны в match
.
Добавились два синтаксических шаблона: один для случаев, когда нужно привязать срез к переменной, другой для случаев, когда просто нужно указать пропущенные элементы. Оба шаблона используют ..
(rest pattern) для соответствия переменному количеству элементов.
Сопоставления с привязкой элементов
Ниже представлена абстрактная функция с набором наиболее интересных шаблонов, конечно она не будет компилироваться!
fn foo(slice: &[&str]) {
match slice {
// сопоставление срезу любой длины
// с привязкой первого и последнего элемента
[x, .., y] => {
println!("First: {:?} and last: {:?}.", x, y)
}
// сопоставление срезу с одним элементом
[x] => {
println!("slice has a single item: {:?}.", x)
}
// сопоставление срезу с тремя элементами
[x, y, z] => {
println!("{:?}, {:?}, {:?}", x, y, z)
}
// сопоставление с привязкой последнего элемента
[.., x] => {
println!("last {:?}", x)
}
// обязательно пустой шаблон, так как длина не известна
_ => {}
}
}
Помните, что ..
соответствует любому кол-ву элементов, включая 0 . Это означает, что первый шаблон соответствует любому срезу, который как минимум включает два элемента.
Сопоставления с привязкой подсреза
Привязка осуществляется с помощью оператора @
.
fn first_and_sum(slice: &[i32]) {
match slice {
[] => {},
[x, subslice @ ..] => {
println!(
"first {:?}, sum of the remaining elements {:?}",
x,
sum(subslice)
)
}
}
}
В приведенном выше примере, если срез не пустой, будет взят первый элемент x
, и посчитана сумма элементов остальной части среза subslice
.
Другой пример - получение элемента в середине среза, при условии, что срез имеет нечетное количество элементов.
fn middle(slice: &[i32]) -> Option<i32> {
match slice {
[_, inner @ .., _] => middle(inner),
[x] => Some(x),
[] => None,
}
}
Используя рекурсию, перебирается срез. Если срез длиннее 3 элементов, тогда пропускается один элемент в начале и один в конце, а срез оставшийся посередине используется в качестве входных данных для следующего шага.
Вывод
Мы разобрали далеко не все доступные функции, за более подробной информацией следует обратиться к Issue #320. slice_patterns
невероятно годное дополнение к стандартному набору шаблонов и будет полезна всякому, кто сталкивается со срезами в повседневной работе.