Adrien Chapelet
Adrien Chapelet

Reputation: 450

Rust print option custom struct

In rust, I want in my impl fmt::Display for MainStruct, to be able to print another struct.

#[derive(Clone, Default)]
pub struct MainStruct {
    pub child: Option<ChildStruct>
}
#[derive(Clone, Default)]
pub struct ChildStruct {
    pub field: String
}

impl std::fmt::Display for MainStruct {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
       write!(f, "MainStruct: child:{}", self.child)
   }
}
impl std::fmt::Display for ChildStruct {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
       write!(f, "ChildStruct: field:{}", self.field)
   }
}

I have tried with the default {} formatter, and with the {:?} formatter, but without any success.

Upvotes: 1

Views: 1931

Answers (2)

Cerberus
Cerberus

Reputation: 10247

Since Option does not implement Display, you have to write some logic yourself to handle two possible cases. The simplest way might be to just match on the Option explicitly:

impl std::fmt::Display for MainStruct {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "MainStruct: child: ")?;
        match self.child.as_ref() {
            Some(child) => write!(f, "Some({})", child),
            None => write!(f, "None"),
        }
    }
}

Here's the playground with a short test case.

Upvotes: 3

enaut
enaut

Reputation: 441

The Problem is that Option<T> has not implemented the Display trait. So you have to get the value out of the option. The easiest to do so is .unwrap(). This however panics if the option is None. (other methods for unpacking are expect, match, …)

If you use .unwrap() the value is moved out of the Option. So the Option would now be invalid as it would not contain anything anymore. The compiler prevents this with an error cannot move out of 'self.child'.

So what you actually want is a reference that does not consume the child. So you want &T or &mut T from the Option. You can do that by using the .as_ref() to convert Option<T> to Option<&T>. Then if you do .unwrap() on that the compiler wont complain anymore as you just copy a &T pointer.

so your code compiles if you change the following:

impl std::fmt::Display for MainStruct {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
       write!(f, "MainStruct: child:{}", self.child.as_ref().unwrap())
   }
}

Upvotes: 2

Related Questions