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?
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)
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.
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 .
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"),
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With