【问题标题】:How to implement Error with a custom struct如何使用自定义结构实现错误
【发布时间】:2020-12-18 17:56:12
【问题描述】:

我一直在关注here

它包含一个看似相关的简化示例,但我的实现并不适合。这里的错误是:returns a reference to data owned by the current function。该示例建议使用结构的特定属性,即String。这很好,因为编译器可以知道该结构将持续多长时间。但是如果我们需要在运行时构建字符串呢?我该如何完成这项工作?

#[derive(Clone, Debug)]
pub enum ReadFailure {
    MissingFile(String),
    BadData(String),
    // ...
}

impl fmt::Display for ReadFailure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ReadFailure::MissingFile(path) => write!(f, "WARNING - File not read (file does not exist): {}", path),
            ReadFailure::BadData(path) => write!(f, "WARNING - File cannot be read (file has bad data): {}", path),
            // ...
        }
    }
}

/// Implements an error for failure to read with a message
#[derive(Clone, Debug)]
pub struct ReadError {
    /// Failure condition
    error: ReadFailure,
}

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.error)
    }
}

impl Error for ReadError {
    fn description(&self) -> &str {
        let s = format!("{}", self.error);
        &s
    }
}

【问题讨论】:

  • 您不必实现description。 rustdoc 说:“自 1.42.0 起已弃用:使用 Display impl 或 to_string()”doc.rust-lang.org/std/error/trait.Error.html#method.description。在实现Display 时您将拥有更大的灵活性,即您可以在Formatter 上使用write_str 方法。
  • @justinas 我要试试这个,但我认为这正是我需要知道的。非常感谢!

标签: error-handling rust traits lifetime borrow-checker


【解决方案1】:

但是如果我们需要在运行时构建字符串呢?我该如何完成这项工作?

只需在创建ReadError 时在运行时构建它,这是一个示例:

use std::fmt;
use std::error::Error;

#[derive(Clone, Debug)]
pub enum ReadFailure {
    MissingFile(String),
    BadData(String),
}

impl fmt::Display for ReadFailure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ReadFailure::MissingFile(path) => write!(f, "WARNING - File not read (file does not exist): {}", path),
            ReadFailure::BadData(path) => write!(f, "WARNING - File cannot be read (file has bad data): {}", path),
        }
    }
}

#[derive(Clone, Debug)]
pub struct ReadError {
    error: ReadFailure,
    description: String, // NEW
}

// NEW
impl ReadError {
    fn new(error: ReadFailure) -> Self {
        ReadError {
            description: error.to_string(),
            error,
        }
    }
}

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.error)
    }
}

impl Error for ReadError {
    fn description(&self) -> &str {
        &self.description
    }
}

fn main() {
    // example
    let error = ReadError::new(ReadFailure::MissingFile("./whatever.txt".to_string()));
    println!("{}", error.description());
}

playground

description 的函数签名中可以清楚地看出,它只是假设是一个只读方法,它返回对错误中某个字段的引用。

无论如何,正如@justinas 在 cmets 中指出的那样,该方法已被弃用,文档建议您实施 Display 特征,而不是您已经在做的。

【讨论】:

  • 是的。我认为真正的解决方案就是实现 Display。如果我必须包含另一个描述,我真的只想将其作为覆盖默认字符串的选项。不过,通过这种设置方式,我认为删除 Error 块更有意义。不过,非常感谢您的回复!
猜你喜欢
  • 1970-01-01
  • 2013-03-21
  • 2013-09-25
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
相关资源
最近更新 更多