Есть ли в Rust заявления о переключении традиционного стиля? - PullRequest
0 голосов
/ 23 апреля 2019

Я хочу сравнить значение с константами или другими значениями.На другом языке (например, JavaScript) я бы сделал:

// Pretend these are values that are generated another way
let a = 23;
let b = 16;
let c = 43;
let input = 23;

switch (input) {
    case a: console.log("Input is equal to a"); break;
    case b: console.log("Input is equal to b"); break;
    case c: console.log("Input is equal to c"); break;
    default: console.log("Input does not equal any value"); break;
}

Как бы я сделал это аккуратно в Rust?Я знаю, что мог бы сделать это с помощью операторов if, но я думаю, что это грязно, и я сравниваю со многими другими значениями.

Могу ли я сравнить переменную с постоянными значениями в Rust с помощью оператора match?

1 Ответ

4 голосов
/ 23 апреля 2019

Самый простой способ сделать такой анализ кейсов - это когда вы заранее знаете значения кейсов и не против их размещения в середине кода.В этом случае вам нужно простое match выражение.

fn main() {
    for &input in &[16, 23, 42, 43] {
        match input {
            23 => println!("Input is equal to a"),
            16 => println!("Input is equal to b"),
            43 => println!("Input is equal to c"),
            _ => println!("Input does not equal any value"),
        }
    }
}

(ссылка на игровую площадку)

Если ваши a b и c - это константы времени компиляции (либо известное значение, либо сгенерированное с помощью const функций), тогда вы все равно можете напрямую сопоставить их.

const A: i32 = 23;
const B: i32 = 16;
const C: i32 = generate_c();

const fn generate_c() -> i32 {
    A + B + 4
}

fn main() {
    for &input in &[16, 23, 42, 43] {
        match input {
            A => println!("Input is equal to a"),
            B => println!("Input is equal to b"),
            C => println!("Input is equal to c"),
            _ => println!("Input does not equal any value"),
        }
    }
}

(ссылка на игровую площадку)

Однако, если вы попробуете это с непостоянными переменными, вы получите странные результаты.

fn generate_c(a: i32, b: i32) -> i32 {
    a + b + 4
}

fn main() {
    let a = 23;
    let b = 16;
    let c = generate_c(a, b);

    for &input in &[16, 23, 42, 43] {
        match input {
            a => println!("Input is equal to a"),
            b => println!("Input is equal to b"),
            c => println!("Input is equal to c"),
            _ => println!("Input does not equal any value"),
        }
    }
}

(ссылка на игровую площадку)

Еслиесли вы запустите это, компилятор выдаст вам много предупреждений о «недостижимых шаблонах», и на выходе все четыре раза будет «Input is равный a».Проблема в том, что левая сторона каждой строки в операторе сопоставления является не просто выражением, а шаблоном .

. Шаблон представляет собой выражение, подобное (x, [_, z], Some(_)).Он состоит из базовых переменных (например, x и z), символов подчеркивания (_), всех литеральных выражений (целых чисел, чисел с плавающей точкой, кортежей, массивов) и нескольких других вещей.

Когда Rust выполняет такой оператор сопоставления, он пытается синтаксически сопоставить входные данные с шаблоном.Базовые переменные будут совпадать с чем угодно, и значение этой переменной будет установлено равным тому, что соответствует области видимости этой ветви оператора сравнения.Символы подчеркивания (используемые во всех приведенных выше примерах) тоже совпадают, но не связывают никакие переменные.

В вышеприведенной версии const константы A B и C равнызаменены соответствующими литеральными значениями повсюду в коде, поэтому входные данные сопоставляются с этими литеральными значениями.

С версией переменной, когда мы сопоставляем с a b и c, эти буквыинтерпретируется как основные переменные, которые соответствуют чему-либо.Значения переменных вообще не учитываются в шаблоне.В коде

let a = 14;
let b = 15;
let c = 16;
let input = 16;
match input {
    a => println!("Input is equal to a"),
    b => println!("Input is equal to b"),
    c => println!("Input is equal to c"),
    _ => println!("Input does not equal any value"),
}

первая ветвь всегда будет соответствовать, давая вводу имя a для области действия ветви.

Если вам нужно сопоставить переменные ab и c, вы можете добавить охрану к каждой ветви.Охранник фильтрует ветку немного больше, добавляя дополнительное условие для соответствия ветви.В этом случае мы сопоставляем что-либо и привязываем его к переменной x, но затем проверяем, что x равно ab и c).

fn generate_c(a: i32, b: i32) -> i32 {
    a + b + 4
}

fn main() {
    let a = 23;
    let b = 16;
    let c = generate_c(a, b);

    for &input in &[16, 23, 42, 43] {
        match input {
            x if x == a => println!("Input is equal to a"),
            x if x == b => println!("Input is equal to b"),
            x if x == c => println!("Input is equal to c"),
            _ => println!("Input does not equal any value"),
        }
    }
}

(ссылка на игровую площадку)

Это немного более многословно, чем конструкция переключателя / корпуса, но я надеюсь, что понятно, что происходит.В каждой ветви переменная x связана с 16, тогда, если она равна переменной A (или B или C), то эта ветвь берется.В противном случае мы пробуем следующую ветку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...