Dopasowanie wzorców (pattern matching) to jeden z najważniejszych mechanizmów językowych w Rust, wywodzący się z języków funkcyjnych. Pozwala ono na deklaratywne, zwięzłe i bezpieczne rozwiązywanie skomplikowanych wariantów wartości, w tym za pomocą dodatkowych warunków (wyrażeń guard), co daje elastyczność i kontrolę nad logiką.
Bez exhaustiveness checking (sprawdzenie wyczerpującego rozważenia wszystkich wariantów) część możliwości algorytmu dopasowania wzorców może być realizowana z błędami. Ponadto, bez zrozumienia kolejności gałęzi i wyrażeń guard, można popełnić błąd albo w logice, albo w wydajności.
W Rust kompilator sprawdza, że wszystkie warianty enum (lub prostsze struktury pattern) są zbadane, lub jest gałąź _. Gałąź może być dodatkowo ograniczona wyrażeniem guard (if po wzorcu), i tylko gdy warunek jest spełniony, "działa". Pozostałe warianty są nieuchwytne. Kolejność gałęzi jest ważna: są sprawdzane od góry do dołu.
Przykład kodu:
enum Message { Hello, Data(i32), Quit, } fn handle(msg: Message) -> &'static str { match msg { Data(n) if n > 10 => "Big Data", Data(_) => "Some Data", Hello => "Greet!", Quit => "Bye", } }
Kluczowe cechy:
Czy gałąź z guard zadziała, jeśli wzorzec pasuje, ale warunek nie jest spełniony?
Nie, w takim przypadku weryfikacja przechodzi do następnej odpowiedniej gałęzi. Pattern + guard to atomarny "filtr"; tylko gdy oba pasują, wykonywane jest ciało gałęzi.
Czy kolejność gałęzi w match wpływa na wydajność?
Tak. Szczególnie przy dużej liczbie podobnych wzorców z guard: kompilator sprawdza gałęzie od góry do dołu, co wpływa na szybkość weryfikacji w czasie działania — częściej spotykane wartości warto przetwarzać wcześniej.
Czy można pominąć exhaustiveness checking, umieszczając tylko gałąź _?
Technicznie tak — jest to dozwolone, ale traci się niezawodność: jeśli typ wykluczy (lub doda) nowe elementy, kompilator nie ostrzeże o nieprzemyślanym przypadku. Lepiej zawsze jawnie przetwarzać ważne, a "_" tylko w ostateczności.
Kod match dla enum z wyrażeniami guard, gdzie wzorzec z guard jest ostatni, ale większość wartości przechodzi bezpośrednio przez wcześniejszą gałąź _, i nigdy nie dociera do odpowiedniego przetwarzania.
Zalety:
_.Wady:
Najpierw wymieniane są najbardziej częste i ważne warianty (z guard), a następnie exhaustively pokrywane są pozostałe — bez zbędnego kodu w "_".
Zalety:
Wady: