Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print! an Option<Box<struct>>?

Tags:

rust

I am trying to print an Option<Box<MyStruct>>, but I get a compile error when trying to implement Display for Option<Box<MyStruct>>.

use std::fmt;

fn main() {
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
    println!("{}", maybe_my_struct);
}

struct MyStruct {
    foo: i32,
}

impl fmt::Display for Option<Box<MyStruct>> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Some(MyStruct) => write!(formatter, "{}", self.foo),
            None => write!(formatter, "No struct"),
        }
    }
}

The error I get is :

error: the impl does not reference any types defined in this crate; 
only traits defined in the current crate can be implemented for arbitrary types [E0117]

I have tried aliasing the Option type, and instead implementing Display for MyOption<Box<MyStruct>>, but that gives the same result. What am I doing wrong?

like image 924
TorelTwiddler Avatar asked May 31 '15 05:05

TorelTwiddler


People also ask

What is Option <> in Rust?

Type Option represents an optional value: every Option is either Some and contains a value, or None , and does not. Option types are very common in Rust code, as they have a number of uses: Initial values. Return values for functions that are not defined over their entire input range (partial functions)

How do you implement display traits?

When interpolating values into a string in a println! call, you use the {} symbols in a format string followed by the variables as arguments. What this is using to insert a user-facing output into the string is the fmt::Display trait.

How do you know if an option is none in Rust?

P: FnOnce(&T) -> bool, Returns None if the option is None , otherwise calls predicate with the wrapped value and returns: Some(t) if predicate returns true (where t is the wrapped value), and. None if predicate returns false .


1 Answers

As you can see, you can't implement a trait you didn't write for a type you didn't write. This is part of what's known as "coherence" and exists to prevent really weird things like linking against a library suddenly causing unrelated parts of your program to change behaviour.

Aliasing Option to MyOption doesn't work either because, as you say, it's an alias. That is, it's just another name for the same thing, it's not an actual, different type.

Now, if you write a wrapper around Option like so:

struct MyOption<T>(Option<T>);

then MyOption will be a new, distinct type that you can implement a trait for. Of course, you'll want to write methods to wrap and unwrap the actual Option you're storing.

... But this is all rather irrelevant since you could also just derive Debug for your struct and use that.

fn main() {
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
    println!("{:?}", Some(maybe_my_struct));
}

#[derive(Debug)]
struct MyStruct {
    foo: i32,
}

Or, if you really want the custom display logic for the Option<Box<MyStruct>> combination, you can use a marker value (this same approach is used by Path in the standard library, incidentally). Like so:

use std::fmt;

fn main() {
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
    println!("{:?}", maybe_my_struct);

    // Instead of displaying directly, display via a custom marker.
    println!("{}", maybe_my_struct.display());
    println!("{}", None::<Box<MyStruct>>.display());
}

#[derive(Debug)]
struct MyStruct {
    foo: i32,
}

// This is the marker we'll use to define our custom Display impl.
struct MmsDisplay<'a>(&'a Option<Box<MyStruct>>);

// This trait lets us extend Option<Box<MyStruct>> with a new method.
trait CustomMmsDisplay {
    fn display<'a>(&'a self) -> MmsDisplay<'a>;
}

impl CustomMmsDisplay for Option<Box<MyStruct>> {
    fn display<'a>(&'a self) -> MmsDisplay<'a> {
        MmsDisplay(self)
    }
}

// And here's the display logic.
impl<'a> fmt::Display for MmsDisplay<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self.0 {
            Some(ref ms) => write!(formatter, "{}", ms.foo),
            None => write!(formatter, "No struct"),
        }
    }
}
like image 154
DK. Avatar answered Sep 17 '22 23:09

DK.