How do I implement fmt :: Display on a typically typed enum in Rust?
I used my linked list using this recursive enum, but now I would like to implement a custom display format for it
use std::fmt;
#[derive(Debug)]
enum List<A> {
Empty,
Cons(A, Box<List<A>>),
}
impl<T> fmt::Display for List<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
List::Empty => write!(f, "()"),
List::Cons(x, ref xs) => write!(f, "({} {})", x, xs),
}
}
}
Mistake
error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied --> src/main.rs:13:59 | 13 | List::Cons(x, ref xs) => write!(f, "({} {})", x, xs), | ^ the trait `std::fmt::Display` is not implemented for `T` | = help: consider adding a `where T: std::fmt::Display` bound = note: required by `std::fmt::Display::fmt`
Here's the rest of my code in case it matters
fn cons<A>(x: A, xs: List<A>) -> List<A> {
return List::Cons(x, Box::new(xs));
}
fn len<A>(xs: &List<A>) -> i32 {
match *xs {
List::Empty => 0,
List::Cons(_, ref xs) => 1 + len(xs),
}
}
fn map<A, B>(f: &Fn(&A) -> B, xs: &List<A>) -> List<B> {
match *xs {
List::Empty => List::Empty,
List::Cons(ref x, ref xs) => cons(f(x), map(f, xs)),
}
}
fn main() {
let xs = cons(1, cons(2, cons(3, List::Empty)));
println!("{}", xs);
println!("{:?}", len(&xs));
let f = |x: &i32| (*x) * (*x);
let ys = map(&f, &xs);
println!("{}", ys);
println!("{}", List::Empty);
}
Expected Result
(1 (2 (3 ()))) 3 (1 (4 (9 ()))) ()
Indeed, what I would like to see is this, but I have absolutely no idea how I would like to get such an output with fmt::Result
(1 2 3) 3 (1 4 9) ()
source to share
Compiler error solution
You are missing value binding. That is, you need to tell Rust what T
can be displayed:
impl<T: fmt::Display> fmt::Display for List<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
List::Empty => write!(f, "()"),
List::Cons(ref x, ref xs) => write!(f, "({} {})", x, xs),
}
}
}
Note that the border is anchored T: fmt::Display
. This basically means: if T
implements fmt::Display
, then List<T>
implements fmt::Display
.
Icing on the cake
I'm not sure if you can get good formatting with a recursive definition. Also, Rust does not guarantee tail-call optimization, so there is always a possibility.
An alternative definition could be:
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
let mut temp = self;
while let List::Cons(ref x, ref xs) = *temp {
write!(f, "{}", x)?;
// Print trailing whitespace if there are more elements
if let List::Cons(_, _) = **xs {
write!(f, " ")?;
}
temp = xs;
}
write!(f, ")")
}
Notice ?
after most of the macros write!
. This basically means: if this one write!
results in an error, return the error now. Otherwise, continue with the function.
source to share