Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Совместимость типов ошибок

При определении собственного типа ошибки есть несколько распространённых соглашений, которым нужно следовать, чтобы быть совместимым с более широкой экосистемой:

  • Реализуйте трейт Error из стандартной библиотеки.
  • Получите Debug через derive и реализуйте Display (это требуется для Error).
  • Реализуйте преобразования From для базовых типов ошибок, чтобы поддержать автоматическое преобразование типов ошибок с помощью ?.
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

use std::error::Error;
use std::io::Read;
use std::{fmt, fs, io};

#[derive(Debug)]
enum ReadUsernameError {
    IoError(io::Error),
    EmptyUsername,
}

impl Error for ReadUsernameError {}

impl fmt::Display for ReadUsernameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::IoError(e) => write!(f, "I/O error: {e}"),
            Self::EmptyUsername => write!(f, "Username file was empty"),
        }
    }
}

impl From<io::Error> for ReadUsernameError {
    fn from(err: io::Error) -> Self {
        Self::IoError(err)
    }
}
  • Любой тип можно использовать как тип ошибки для Result: нет требований к трейтам, подходят и структуры, и перечисления, а когда ошибке не нужно нести никаких данных, можно даже использовать пустые типы нулевого размера, например ().

  • Хотя строгих требований к типам ошибок нет, для совместимости с экосистемой есть несколько соглашений, которым стоит следовать.

  • Мы уже видели, как трейт From можно использовать для автоматического преобразования типов ошибок с помощью оператора ?.

  • Стандартная библиотека предоставляет маркерный трейт Error, чтобы показать, что тип представляет ошибку.

  • Error зависит от Debug (который можно получить через derive) и Display (который нужно реализовать вручную). Они гарантируют, что ошибку всегда можно превратить в строку для логирования или показа пользователю.

  • Трейт Error сам по себе не предоставляет никакой функциональности, но в нескольких слайдах мы посмотрим, как Error можно использовать для создания динамических типов ошибок.

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