3

I am writing a basic binary tree structure and I want to display a node. It seems that Rust has trouble displaying a generic type, and I get this error:

error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
  --> src/main.rs:55:60
   |
55 |         write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
   |                                                            ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
   |
   = help: consider adding a `where T: std::fmt::Display` bound
   = note: required by `std::fmt::Display::fmt`

error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
  --> src/main.rs:62:60
   |
62 |         write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
   |                                                            ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
   |
   = help: consider adding a `where T: std::fmt::Display` bound
   = note: required by `std::fmt::Display::fmt`

Here's the full code, including the iterators

struct Node<T> {
    data: T,
    left: Option<Box<Node<T>>>,
    right: Option<Box<Node<T>>>,
}

struct NodeIterator<T> {
    nodes: Vec<Node<T>>,
}

struct Tree<T> {
    root: Option<Node<T>>,
}

impl<T> Node<T> {
    pub fn new(value: Option<T>,
               left: Option<Box<Node<T>>>,
               right: Option<Box<Node<T>>>)
               -> Node<T> {
        Node {
            data: value.unwrap(),
            left: left,
            right: right,
        }
    }

    pub fn insert(&mut self, value: T) {
        println!("Node insert");
        match self.left {
            Some(ref mut l) => {
                match self.right {
                    Some(ref mut r) => {
                        r.insert(value);
                    } 
                    None => {
                        self.right = Some(Box::new(Node::new(Some(value), None, None)));
                    }
                }
            }
            None => {
                self.left = Some(Box::new(Node::new(Some(value), None, None)));
            }
        }
    }
}

impl<T> std::fmt::Display for Node<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f,
               "Node data: {} left: {:?}, right: {:?}",
               self.data,
               self.left,
               self.right);
    }
}

impl<T> std::fmt::Debug for Node<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f,
               "Node data: {} left: {:?}, right: {:?}",
               self.data,
               self.left,
               self.right);
    }
}

impl<T> Iterator for NodeIterator<T> {
    type Item = Node<T>;
    fn next(&mut self) -> Option<Node<T>> {
        if self.nodes.len() == 0 {
            None
        } else {
            let current: Option<Node<T>> = self.nodes.pop();
            for it in current.iter() {
                for n in it.left.iter() {
                    self.nodes.push(**n);
                }
                for n in it.right.iter() {
                    self.nodes.push(**n);
                }
            }
            return current;
        }
    }
}

impl<T> Tree<T> {
    pub fn new() -> Tree<T> {
        Tree { root: None }
    }

    pub fn insert(&mut self, value: T) {
        match self.root {
            Some(ref mut n) => {
                println!("Root is not empty, insert in node");
                n.insert(value);
            }
            None => {
                println!("Root is empty");
                self.root = Some(Node::new(Some(value), None, None));
            }
        }
    }

    fn iter(&self) -> NodeIterator<T> {
        NodeIterator { nodes: vec![self.root.unwrap()] }
    }
}

fn main() {
    println!("Hello, world!");

    let mut tree: Tree<i32> = Tree::new();
    tree.insert(42);
    tree.insert(43);

    for it in tree.iter() {
        println!("{}", it);
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
bl4ckb0ne
  • 1,097
  • 2
  • 15
  • 30
  • 4
    You need to supply the `where T: std::fmt::Display` type constraint to your types all the way down. That said, there are quite a few other issues with your code. The obvious one is that the `write!` lines end in a semi colon and so those methods don't return the result from the `write!` calls. You're also going to hit ownership issues and so you'll need to either `#[derive(Clone)]`, `clone()` and `+ std::clone::Clone` the type constraints in all of the places that happens. Containers like this aren't trivial in Rust and require a deep understanding of the type system to pull off. – Simon Whitehead Nov 15 '16 at 04:48

1 Answers1

11

Here is a minimal version of this issue:

struct Bob<T>(T);

impl<T> std::fmt::Display for Bob<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Bob: {}", self.0)
    }
}

fn main() {
    let x = Bob(4);
    println!("{}", x);
}

Let's take a look at our fmt function:

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    write!(f, "Bob: {}", self.0)
}

We can rewrite it as follows for better clarity:

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    write!(f, "Bob: ")?;
    std::fmt::Display::fmt(&self.0, f)
}

Calling one of the formatting macros (write!, format!, println!, etc.) with double brackets in quotes, "{}", says to call the fmt function from the Display trait for that argument (self.0 in this case).

The problem is that we have some generic type T, so the compiler has no idea whether Display is implemented for it or not.

There are two ways to fix this.

First, we could add the constraint T: std::fmt::Display to our implementation of Display for Bob. This will let us use the struct with non-Display types, but Display will only be implemented when we use it with Display types.

That fix looks like this:

impl<T: std::fmt::Display> std::fmt::Display for Bob<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Bob: {}", self.0)
    }
}

Second, we could add that constraint to the struct definition, like this:

struct Bob<T: std::fmt::Display>(T);

This will mean that Bob is only generic with regards to types that are Display. It is more limiting and restricts the flexibility of Bob, but there may be cases where that is desired.


There are other traits similar to Display that can be called by putting different tokens in the brackets. The full list can be found in the documentation, but, for example, we could use the Debug trait with

write!(f, "Bob: {:?}", self.0)

only then we would need to be sure that T is std::fmt::Debug.

Community
  • 1
  • 1
paholg
  • 1,910
  • 17
  • 19
  • Is it the same fix for `std::fmt::Debug`? rustc is also giving me the error E0277 – bl4ckb0ne Nov 15 '16 at 05:09
  • Yes. It's the same fix any time you get error 0277. – paholg Nov 15 '16 at 05:53
  • `impl std::fmt::Debug for Node` doesn't seems to be working. `error[E0277]: the trait bound 'T: std::fmt::Display' is not satisfied` – bl4ckb0ne Nov 15 '16 at 19:33
  • @Bl4ckb0ne You likely need both. I prefer a `where` clause in this instance: `...for Node where T: std::fmt::Debug + std::fmt::Display`. – Simon Whitehead Nov 15 '16 at 19:59
  • @SimonWhitehead so I only need 1 fmt for both `Debug` and `Display` ? – bl4ckb0ne Nov 15 '16 at 20:05
  • @Bl4ckb0ne In your `Debug` implementation, you still call out to `self.data`'s `Display` implementation. So, for what you have, you'd need `impl std::fmt::Debug for Node`. I have tried to make this more clear in my answer. – paholg Nov 15 '16 at 20:26