Поиск…


Синтаксис

  • _ // шаблон шаблона, соответствует чему-либо¹
  • идентификатор // шаблон привязки, сопоставляет все и связывает его с идентификатором ¹
  • ident @ pat // то же, что и выше, но позволяет дополнительно сопоставлять то, что привязано
  • ref ident // шаблон привязки, сопоставляет что-либо и связывает его с ссылочным идентификатором ¹
  • ref mut ident // шаблон привязки, сопоставляет все и связывает его с изменяемым ссылочным идентификатором ¹
  • & pat // соответствует ссылке (поэтому pat не является ссылкой, но рефери) ¹
  • & mut pat // то же, что и выше, с изменяемой ссылкой¹
  • CONST // соответствует именованной константе
  • Struct {поле1, Field2} // спички и разбирает значение структуры, см ниже замечание о fields¹
  • EnumVariant // соответствует варианту перечисления
  • EnumVariant ( pat1 , pat2 ) // соответствует варианту перечисления и соответствующим параметрам
  • EnumVariant ( pat1 , pat2 , .., patn ) // то же, что и выше, но пропускает все, кроме первого, второго и последнего параметров
  • ( pat1 , pat2 ) // соответствует кортежу и соответствующим элементам¹
  • ( pat1 , pat2 , .., patn ) // то же, что и выше, но пропускает все, кроме первого, второго и последнего элементов¹
  • lit // соответствует литеральной константе (char, числовые типы, логические и строковые)
  • pat1 ... pat2 // соответствует значению в этом ( включенном ) диапазоне (char и числовые типы)

замечания

При деконструкции структурного значения поле должно быть либо типа поля field_name либо field_name : pattern . Если шаблон не указан, выполняется неявное связывание:

let Point { x, y } = p;
// equivalent to
let Point { x: x, y: y } = p;

let Point { ref x, ref y } = p;
// equivalent to
let Point { x: ref x, y: ref y } = p;

1: необратимый шаблон

Согласование шаблонов с привязками

Можно привязывать значения к именам, используя @ :


struct Badger {
    pub age: u8
}

fn main() {
    // Let's create a Badger instances
    let badger_john = Badger { age: 8 };

    // Now try to find out what John's favourite activity is, based on his age
    match badger_john.age {
        // we can bind value ranges to variables and use them in the matched branches
        baby_age @ 0...1 => println!("John is {} years old, he sleeps a lot", baby_age),
        young_age @ 2...4 => println!("John is {} years old, he plays all day", young_age),
        adult_age @ 5...10 => println!("John is {} years old, he eats honey most of the time", adult_age),
        old_age => println!("John is {} years old, he mostly reads newspapers", old_age),
    }
}

Это напечатает:

John is 8 years old, he eats honey most of the time

Базовое совпадение

// Create a boolean value
let a = true;

// The following expression will try and find a pattern for our value starting with
// the topmost pattern. 
// This is an exhaustive match expression because it checks for every possible value
match a {
  true => println!("a is true"),
  false => println!("a is false")
}

Если мы не рассмотрим все случаи, мы получим ошибку компилятора:

match a {
  true => println!("most important case")
}
// error: non-exhaustive patterns: `false` not covered [E0004]

Мы можем использовать _ в качестве аргумента default / wildcard, он соответствует всем:

// Create an 32-bit unsigned integer
let b: u32 = 13;

match b {
  0 => println!("b is 0"),
  1 => println!("b is 1"),
  _ => println!("b is something other than 0 or 1")
}

В этом примере будет напечатан:

a is true
b is something else than 0 or 1

Согласование нескольких шаблонов

Можно обрабатывать несколько разных значений одинаковым образом, используя | :

enum Colour {
    Red,
    Green,
    Blue,
    Cyan,
    Magenta,
    Yellow,
    Black
}

enum ColourModel {
    RGB,
    CMYK
}

// let's take an example colour
let colour = Colour::Red;

let model = match colour {
    // check if colour is any of the RGB colours
    Colour::Red | Colour::Green | Colour::Blue => ColourModel::RGB,
    // otherwise select CMYK
    _ => ColourModel::CMYK,
};

Условное сопоставление шаблонов с защитой

Шаблоны могут быть сопоставлены на основе значений, не зависящих от сопоставления значения с использованием, if защита:

// Let's imagine a simplistic web app with the following pages:
enum Page {
  Login,
  Logout,
  About,
  Admin
}

// We are authenticated
let is_authenticated = true;

// But we aren't admins
let is_admin = false;

let accessed_page = Page::Admin;

match accessed_page {
    // Login is available for not yet authenticated users
    Page::Login if !is_authenticated => println!("Please provide a username and a password"),

    // Logout is available for authenticated users 
    Page::Logout if is_authenticated => println!("Good bye"),
    
    // About is a public page, anyone can access it
    Page::About => println!("About us"),

    // But the Admin page is restricted to administators
    Page::Admin if is_admin => println!("Welcome, dear administrator"),

    // For every other request, we display an error message
    _ => println!("Not available")
}

Появится сообщение «Недоступно» .

если пусть / пусть пусть


if let

Объединяет match шаблонов и оператор if и позволяет выполнять короткие неисчерпывающие совпадения.

if let Some(x) = option {
    do_something(x);
}

Это эквивалентно:

match option {
    Some(x) => do_something(x),
    _ => {},
}

Эти блоки также могут содержать инструкции else .

if let Some(x) = option {
    do_something(x);
} else {
    panic!("option was None");
}

Этот блок эквивалентен:

match option {
    Some(x) => do_something(x),
    None => panic!("option was None"),
}

while let

Объединяет совпадение шаблонов и цикл while.

let mut cs = "Hello, world!".chars();
while let Some(x) = cs.next() {
    print("{}+", x);
}
println!("");

Это печатает H+e+l+l+o+,+ +w+o+r+l+d+!+ .

Это эквивалентно использованию loop {} и match заявление:

let mut cs = "Hello, world!".chars();
loop {
    match cs.next() {
        Some(x) => print("{}+", x),
        _ => break,
    }
}
println!("");

Извлечение ссылок из шаблонов

Иногда необходимо иметь возможность извлекать значения из объекта, используя только ссылки (т. Е. Без передачи права собственности).

struct Token {
  pub id: u32
}

struct User {
  pub token: Option<Token>
}


fn main() {
    // Create a user with an arbitrary token
    let user = User { token: Some(Token { id: 3 }) };

    // Let's borrow user by getting a reference to it
    let user_ref = &user;

    // This match expression would not compile saying "cannot move out of borrowed
    // content" because user_ref is a borrowed value but token expects an owned value.
    match user_ref {
        &User { token } => println!("User token exists? {}", token.is_some())
    }

    // By adding 'ref' to our pattern we instruct the compiler to give us a reference
    // instead of an owned value.
    match user_ref {
        &User { ref token } => println!("User token exists? {}", token.is_some())
    }

    // We can also combine ref with destructuring
    match user_ref {
        // 'ref' will allow us to access the token inside of the Option by reference
        &User { token: Some(ref user_token) } => println!("Token value: {}", user_token.id ),
        &User { token: None } => println!("There was no token assigned to the user" )
    }

    // References can be mutable too, let's create another user to demonstrate this
    let mut other_user = User { token: Some(Token { id: 4 }) };

    // Take a mutable reference to the user
    let other_user_ref_mut = &mut other_user;

    match other_user_ref_mut {
        // 'ref mut' gets us a mutable reference allowing us to change the contained value directly.
        &mut User { token: Some(ref mut user_token) } => {
            user_token.id = 5;
            println!("New token value: {}", user_token.id )
        },
        &mut User { token: None } => println!("There was no token assigned to the user" )
    }
}

Он напечатает это:

User token exists? true
Token value: 3
New token value: 5


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow