2

Problem


I am trying to implement the std::error::Error trait on a enum. Some elements of the enum are Enum Variants, and I would like to generate a different error message containing the data from the variant. However with the implementation below the formatted String that Deref to &str don't live long enough.

The general solution is to return a String. However, this is not an option here as the returned type must be &str as specified by the Error trait.


Example: Playground link


It is important to note that the variants may not contain usize, and might instead be another enum, or struct etc.

use std::fmt;
use std::fmt::{Display, Formatter};
use std::error;

#[derive(Debug)]
enum EnumError {
    A,
    B(usize),
    C(usize),
    D,
}

impl error::Error for EnumError {
    fn description(&self) -> &str {
        use EnumError::*;
        match *self {
            A => "A happened",
            B(value) => &*format!("B happened info: {:?}", value),
            C(value) => &*format!("B happened info: {:?}", value),
            D => "D happened",
        }
    }
}

impl Display for EnumError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    use std::error::Error;
        write!(f, "{}", self.description())
    }
}

fn main() {}
XAMPPRocky
  • 3,160
  • 5
  • 25
  • 45
  • 1
    It's not a duplicate. The answer in the referenced question suggests returning an owned string - that's not an option here because the return type is specified by the trait. I was in the middle of writing an answer to this problem when the question was suddenly closed, it's very frustrating. I edited the question to make the point clear. – Malcolm Jan 16 '16 at 15:24
  • @Malcolm there is simply no way to return a string slice of something created inside a function. I didn't vote for closing but I can't see any solution here except for storing the pre-formatted error string inside the enum itself, which is pretty unwieldy. – Vladimir Matveev Jan 16 '16 at 15:52
  • @VladimirMatveev You named both options, this is exactly what I was going to put into my answer. That would be helpful. Directing to a question with an answer which suggests something that can't be done doesn't help at all. – Malcolm Jan 16 '16 at 15:54
  • @Malcolm - looks like you got your wish – APC Jan 16 '16 at 16:25

1 Answers1

4

The string you create needs to be owned by something. When you create a local string in the method, you have to transfer its ownership to the caller. But since you have to return &str, this is not an option.

The way around it would be to store the string in the struct itself. You can declare the enum value as B(usize, String), put the description there when you create it, and then return it with

B(_, ref descr) => descr

To be frank, description is not supposed to be a terribly detailed message, it just needs to give a general description of what kind of error this is, this is why it returns &str. I didn't see instances of writing any dynamic data into the description in the standard library, usually it's just a static string. Display implementation is a different matter though, in there you can be much more verbose.

Malcolm
  • 41,014
  • 11
  • 68
  • 91