Про що цей оператор знака запитання?


Відповіді:


145

Як ви могли помітити, Руст не має винятків. У нього є паніка, але їх функціональність обмежена (вони не можуть нести структуровану інформацію), і їх використання для обробки помилок не рекомендується (вони призначені для невиправлених помилок).

У Rust використовується обробка помилок Result. Типовим прикладом може бути:

fn halves_if_even(i: i32) -> Result<i32, Error> {
    if i % 2 == 0 {
        Ok(i / 2)
    } else {
        Err(/* something */)
    }
}

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = match halves_if_even(i) {
        Ok(i) => i,
        Err(e) => return Err(e),
    };

    // use `i`
}

Це чудово, оскільки:

  • при написанні коду ви не можете випадково забути впоратися з помилкою,
  • читаючи код, ви можете відразу побачити, що тут є помилка.

Однак це менш ніж ідеально, оскільки це дуже багатослівно. Тут з’являється оператор знака запитання ?.

Вищевказане можна переписати як:

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = halves_if_even(i)?;

    // use `i`
}

що набагато лаконічніше.

Те, ?що тут, еквівалентно matchтвердженню вище. Коротше кажучи: він розпаковує Resultif OK і повертає помилку, якщо ні.

Це трохи магія, але для обробки помилок потрібна певна магія, щоб знищити шаблон, і на відміну від винятків, одразу видно, які виклики функцій можуть, а можуть і не помилитися: ті, що прикрашені ?.

Одним із прикладів магії є те, що це також працює для Option:

// Assume
// fn halves_if_even(i: i32) -> Option<i32>

fn do_the_thing(i: i32) -> Option<i32> {
    let i = halves_if_even(i)?;

    // use `i`
}

Це забезпечується (нестійкою) Tryознакою.

Дивіться також:


5
було б непогано, якби ви могли трохи розширити свою відповідь, наприклад, обговорити, що тип повернення функції повинен відповідати типу, який ви намагаєтесь "розгортати", наприклад Resultабо Option.
hellow

@hellow Я гадаю, що краще взагалі буде новим питанням
Пол Разван Берг

2

Він призначений для поширення помилок для відновлюваного типу помилки Результат <T, E>. Це розгортає результат і надає вам внутрішню цінність.

Замість того, щоб обробляти випадки помилки, ви розповсюджуєте їх на код абонента і маєте справу лише з випадком Ok. Перевага полягає в тому, що це усуває велику кількість шаблонів та спрощує реалізацію функції.


не плутати з фактичним, .unwrap()який панікує у випадку помилки.
Йорданія
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.