Book section Multiple trait bounds debug style :? questions


#1

Consider the modified book code below.
fn main() {
use std::fmt::Debug;

fn bar<T, K>(x: T, y: K)
    where T: Clone,
          K: Clone + Debug {

    x.clone();
    y.clone();
    //println!("Inner x is {}", x);
    println!("y is {:?}", y);
}

let aa = 5;
let bb = 10;
let cc = 15;

bar(aa, bb);
println!("cc is {}", cc);

let x = 5;
let y = 10;

println!("Last x and y: {} and {}", x, y);

}

Result:

y is 10
cc is 15
Last x and y: 5 and 10

If I uncomment the line "//println!(“Inner x is {}”, x);"
it will not compile, giving this error on the innter ‘x’ println statement:
error: the trait core::fmt::Debug is not implemented for the type T

But x (as type T) should be an inferred i32, right? The clone of it does not seem to infer it, but I am not sure that is the problem. In any case I expected the print of the cloned x to work the same as the println for “Last x…” line, with the cloned x being inferred by rust as an i32.

Is there a general rule for this? Please comment.

Thanks


#2

If you modify the function definition to be:

fn bar<T, K>(x: T, y: K)
    where T: Clone + Debug,
          K: Clone + Debug {

And in the println!:

println!("Inner x is {:?}", x);

Things work again. There is no inferring types across function calls so when bar() is compiled it just uses what is know about T, i.e. it implements Clone and that K implements Clone and Debug. If you tell the compiler that T also implements Debug, then it can be used in the println!. And the compiler will make sure that you call bar with two parameters that implement both Clone and Debug.

You could also edit the function definition to be:

fn bar<T, K>(x: T, y: K)
    where T: Clone + Display,
          K: Clone + Display {

Then you can use println!'s i’m used to seeing:

println!("Inner x is {}", x);
println!("y is {}", y);

#3

Ah, no inferring across functions. Okay.

New question, same code. Why do I need :? for Debug but not for Display? What does :? in the println statement signal the compiler?

Thanks


#4

In the above Ah, … question, I am referring to this slightly modified code.

use std::fmt::Debug;
use std::fmt::Display;

fn main() {

fn bar<T, K>(x: T, y: K)
    where T: Clone + Display,
          K: Clone + Debug {

    x.clone();
    y.clone();
    println!("Inner x is {}", x);
    println!("y is {:?}", y);
}

let aa = 5;
let bb = 10;
let cc = 15;

bar(aa, bb);
println!("cc is {}", cc);

let x = 5;
let y = 10;

println!("Last x and y: {} and {}", x, y);

}

Results:
Inner x is 5
y is 10
cc is 15
Last x and y: 5 and 10


#5

Display is used for outputting a value to the user. Debug is used for debug prints and (which is super awesome, btw) can be derived automatically.

In the format strings {} uses Display for output and {:?} uses Debug. There is aslo {:#?} which pretty prints debug representation, which is handy in case of nested structs. Here is an example, note derive(Debug).

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32
}

impl std::fmt::Display for Point {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Point {x: 92, y: 1};
    println!("{}\n", p);
    println!("{:?}\n", p);
    println!("{:#?}", p);
}

which outputs

(92, 1)

Point { x: 92, y: 1 }

Point {
    x: 92,
    y: 1
}

#6

Excellent.
And such quick replies. Thanks to you all!