Определение типа ошибок

RustRustBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабе мы изучаем, как определить пользовательский тип ошибок в Rust и ключевые характеристики, которые делают хороший тип ошибок, такие как представление различных ошибок одним типом, предоставление ясных сообщений об ошибках, простое сравнение с другими типами и возможность хранения информации об ошибке. Мы также изучаем пример кода, демонстрирующий реализацию пользовательского типа ошибок и его использование в сценариях обработки ошибок.

Примечание: Если лаб не задает имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать main.rs, скомпилировать и запустить его с помощью rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/traits("Traits") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99247{{"Определение типа ошибок"}} rust/integer_types -.-> lab-99247{{"Определение типа ошибок"}} rust/string_type -.-> lab-99247{{"Определение типа ошибок"}} rust/function_syntax -.-> lab-99247{{"Определение типа ошибок"}} rust/expressions_statements -.-> lab-99247{{"Определение типа ошибок"}} rust/lifetime_specifiers -.-> lab-99247{{"Определение типа ошибок"}} rust/method_syntax -.-> lab-99247{{"Определение типа ошибок"}} rust/traits -.-> lab-99247{{"Определение типа ошибок"}} rust/operator_overloading -.-> lab-99247{{"Определение типа ошибок"}} end

Определение типа ошибок

Иногда упрощает код скрыть все разные ошибки одним типом ошибок. Мы покажем это на примере пользовательской ошибки.

Rust позволяет определять собственные типы ошибок. В общем, "хороший" тип ошибок:

  • Представляет разные ошибки одним типом
  • Предоставляет удобные сообщения об ошибках для пользователя
  • Легко сравнивается с другими типами
    • Хорошо: Err(EmptyVec)
    • Плохо: Err("Please use a vector with at least one element".to_owned())
  • Может хранить информацию об ошибке
    • Хорошо: Err(BadChar(c, position))
    • Плохо: Err("+ cannot be used here".to_owned())
  • Хорошо сочетается с другими ошибками
use std::fmt;

type Result<T> = std::result::Result<T, DoubleError>;

// Определяем наши типы ошибок. Они могут быть настроены для наших случаев обработки ошибок.
// Теперь мы сможем писать собственные ошибки, отдавать управление ошибке нижележащему
// реализации или что-то между ними.
#[derive(Debug, Clone)]
struct DoubleError;

// Генерация ошибки полностью отделена от того, как она отображается.
// Не нужно беспокоиться, что сложная логика будет мешаться стилем отображения.
//
// Обратите внимание, что мы не храним никакой дополнительной информации о ошибках.
// Это означает, что мы не можем указать, какая строка не прошла разбор, не изменив наши типы,
// чтобы они хранили эту информацию.
impl fmt::Display for DoubleError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid first item to double")
    }
}

fn double_first(vec: Vec<&str>) -> Result<i32> {
    vec.first()
        // Меняем ошибку на наш новый тип.
     .ok_or(DoubleError)
     .and_then(|s| {
            s.parse::<i32>()
                // Также обновляем на новый тип ошибки здесь.
             .map_err(|_| DoubleError)
             .map(|i| 2 * i)
        })
}

fn print(result: Result<i32>) {
    match result {
        Ok(n) => println!("The first doubled is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    print(double_first(numbers));
    print(double_first(empty));
    print(double_first(strings));
}

Резюме

Поздравляем! Вы завершили лабу по Определению типа ошибок. Вы можете практиковаться в других лабах в LabEx, чтобы улучшить свои навыки.