Два варианта печати исходной ошибки в реализации Display
создают две школы дизайна. На данный момент, ни один из них не является более выраженным c, чем другой , хотя мнения в отношении обоих путей существуют, и в конечном итоге можно будет достичь консенсуса в сообществе в будущем или, возможно, уже так в будущем. контекст конкретного проекта или кодовой базы.
Руководящие принципы Rust API не содержат мнения о Display
в ошибках, кроме C -GOOD-ERR , в котором просто говорится сообщение типа ошибки Display
должно быть "строчными буквами без конечной пунктуации и обычно кратким" . Ожидается предложение по обновлению данного руководства, в котором разработчикам предлагается исключить source
из Display
подразумеваемых. Опять же, предложение не существует без некоторых трений.
Что можно сделать здесь и сейчас, так это объективно указать ключевые различия между ними, при этом прояснив несколько возможных заблуждений.
1. Да, включите source
в свой Display
impl
Пример с SNAFU:
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not read data set token: {}", source))]
ReadToken {
#[snafu(backtrace)]
source: ReadDataSetError,
},
}
Ключевое преимущество, как уже упоминалось в вопросе, заключается в том, что предоставляется полный объем информации так же просто, как просто распечатать значение ошибки.
eprintln!("[ERROR] {}", err);
Это просто и легко, не требуя вспомогательных функций для сообщения об ошибке, хотя и с недостаточной гибкостью представления. Без обработки строк вы получите цепочку ошибок, разделенных двоеточиями.
[ERROR] Could not read data set token: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
2. Нет, не указывайте source
на вашем Display
impl
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not read data set token"))]
ReadToken {
#[snafu(backtrace)]
source: ReadDataSetError,
},
}
Хотя это не даст вам полной информации с помощью однострочной печати, как раньше, вы можете оставить эту задачу для ошибки всего проекта репортер. Это также дает потребителю API большую гибкость при представлении ошибок.
Ниже приводится простой пример. Для представления трассировки ошибки потребуются дополнительные logi c.
fn report<E: 'static>(err: E)
where
E: std::error::Error,
E: Send + Sync,
{
eprintln!("[ERROR] {}", err);
if let Some(cause) = err.source() {
eprintln!();
eprintln!("Caused by:");
for (i, e) in std::iter::successors(Some(cause), |e| e.source()).enumerate() {
eprintln!(" {}: {}", i, e);
}
}
}
Также стоит учитывать интерес интеграции с самоуверенными библиотеками. То есть некоторые ящики в экосистеме, возможно, уже сделали предположение о том, какой вариант выбрать. В anyhow
отчеты об ошибках уже будут проходить по цепочке источников ошибок по умолчанию. При использовании anyhow
для сообщения об ошибках вы должны не добавлять source
, иначе вы можете получить раздражающий список повторяющихся сообщений:
[ERROR] Could not read data set token: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
Caused by:
0: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
1: Undefined value length of element tagged (5533,5533) at position 3548
Аналогично, * Библиотека 1053 *eyre
предоставляет настраиваемую абстракцию отчетов об ошибках, но существующие средства отчетности об ошибках в экосистеме ящиков eyre
также предполагают, что источник не распечатывается реализацией ошибки Display
.
В в любом случае ...
Это решение играет роль только в сообщении об ошибках, а не в сопоставлении ошибок или обработке ошибок каким-либо другим образом. Существование метода source
устанавливает цепную структуру для всех типов ошибок, которая может быть использована при сопоставлении с образцом и последующем управлении потоком программы. Метод Error::source
имеет цель в экосистеме, независимо от того, как сообщается об ошибках.