ПрограммированиеRust разработчик

Как работают pattern matching и destructuring в Rust, и какие тонкости нужно учитывать при их использовании?

Проходите собеседования с ИИ помощником Hintsage

Ответ

Pattern matching в Rust позволяет разбивать значения по структуре, анализировать и обрабатывать сложные типы с помощью конструкций match, if let, while let. Деструктуризация (разложение на части) удобна для работы с кортежами, структурами, enum'ами и даже ссылками.

Пример с enum:

enum Message { Quit, ChangeColor(i32, i32, i32), Write(String), } let m = Message::ChangeColor(255, 0, 0); match m { Message::Quit => println!("Quit!"), Message::ChangeColor(r, g, b) => println!("Color: {} {} {}", r, g, b), Message::Write(text) => println!("Text: {}", text), }

Деструктуризация структур:

struct Point { x: i32, y: i32 } let p = Point { x: 10, y: 20 }; let Point { x, y } = p;

Тонкости:

  • Использование ref и ref mut позволяет получить ссылки при разложении.
  • С помощью @ можно "переименовать" часть паттерна.
  • Матчинг по значениям, диапазонам, условиям (if guard).
  • При деструктуризации ссылок (&SomeType) — важно помнить о владении и borrowing.

Вопрос с подвохом

Можно ли всегда использовать "_" (подчеркивание) чтобы игнорировать части паттерна и избежать предупреждений компилятора?

Не всегда. Подчеркивание действительно пропускает значение, но если не обрабатывать все варианты enum'а и использовать "_" для catch-all, вы можете упустить обработку новых вариантов при расширении enum в будущем. Лучше всегда явно перечислять важные варианты, чтобы компилятор предупредил о нерассмотренных случаях!

match result { Ok(val) => ..., Err(err) => ..., //_ => ... // не рекомендуется для enum! }

Примеры реальных ошибок из-за незнания тонкостей темы


История

В приложении IoT устройство перестало отвечать из-за того, что при добавлении нового варианта enum в месте pattern matching использовался catch-all "_". Ошибка осталась невидимой до деплоя. После этого критичные enum'ы всегда разбирались только с явным перебором вариантов.


История

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


История

В одном функционале передачи сообщений между потоками использовали деструктуризацию через if-let, но игнорировали редкие варианты enum. При появлении новой бизнес-логики сообщения просто терялись. После этого в командном стиле было заведено правило — каждое match выражение должно быть исчерпывающим без catch-all.