Какой механизм допускает сбой :: Ошибка для представления всех ошибок? - PullRequest
3 голосов
/ 30 апреля 2019

Например:

extern crate failure;

use std::fs::File;

fn f() -> std::result::Result<(), failure::Error> 
    let _ = File::open("test")?;
    "123".parse::<u32>()?;
    Ok(())
}

Какой метод позволяет failure::Error представлять std::io::Error, ошибку синтаксического анализа и любые другие пользовательские типы ошибок?Какова минимальная реализация для воссоздания этой способности?

Ответы [ 2 ]

2 голосов
/ 30 апреля 2019

Здесь задействованы два механизма.

Первым механизмом является оператор вопросительного знака, который возвращает Err(From::from(e)) при обнаружении Err(e).Если тип возвращаемого значения функции Result<T, E>, это позволяет нам возвращать любой тип ошибки F, который E реализует From<F> для.

Из документации типа failure::Error мы можем видетьчто существует универсальная реализация From для всех типов, реализующих failure::Fail признак , и существует универсальная реализация Fail для всех типов, реализующих std::error::Error (какпока они тоже Send + Sync + 'static).В сочетании это позволяет нам возвращать любой тип, реализующий черту failure::Fail или черту std::error::Error.Все типы ошибок в стандартной библиотеке реализуют черту Error, включая std::io::Error и std::num::ParseIntError.

Это уже объясняет, почему код компилируется, но не объясняет, как преобразования работают внутренне.Это объясняется вторым механизмом в игре - чертой объектов.Определение (слегка отредактированное) типа Error в ящике failure заключается в следующем:

struct Error {
    imp: ErrorImpl,
}

struct ErrorImpl {
    inner: Box<Inner<dyn Fail>>,
}

struct Inner<F: ?Sized + Fail> {
    backtrace: Backtrace,
    failure: F,
}

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

1 голос
/ 30 апреля 2019

Конструктор failure::Error::from_boxed_compat используется для преобразования любой ошибки в failure::Error.

pub fn from_boxed_compat(err: Box<dyn StdError + Sync + Send + 'static>) -> Error

Эта функция принимает в качестве входных данных любую структуру, которая подразумевает ошибку, и создает failure::Error * 1008.*

failure::Error содержит внутри себя хранящийся в куче объект черты, который может хранить структуру, реализующую объект Error.

struct ErrorImpl {
    inner: Box<Inner<Fail>>,
}

Кроме того, похоже, что Fail trait реализован для многих ошибок.Оператор ? добавит метод into, который преобразует ошибку в failure::Error

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