What is the difference between <T: Trait> Box<T> and &Trait / Box<Trait>?

Viewed 1246

When writing code with traits you can put the trait in a trait bound:

use std::fmt::Debug;

fn myfunction1<T: Debug>(v: Box<T>) {
    println!("{:?}", v);
}

fn myfunction2<T: Debug>(v: &T) {
    println!("{:?}", v);
}

fn main() {
    myfunction1(Box::new(5));
    myfunction2(&5);
}

Or directly in a Box or reference type:

use std::fmt::Debug;

fn myfunction3(v: Box<Debug>) {
    println!("{:?}", v);
}

fn myfunction4(v: &Debug) {
    println!("{:?}", v);
}

fn main() {
    myfunction3(Box::new(5));
    myfunction4(&5);
}

These give the same output. So what is the difference?

(This question was inspired by another question where this was just one of several intermingled concepts)

2 Answers

Importantly, you don't have to put the generic type behind a reference (like & or Box), you can accept it directly:

fn myfunction3<T: Debug>(v: T) {
    println!("{:?}", v);
}

fn main() {
    myfunction3(5);
}

This has the same benefits of monomorphization without the downside of additional memory allocation (Box) or needing to keep ownership of the value somewhere (&).

I would say that generics should often be the default choice — you only require a trait object when there is dynamic dispatch / heterogeneity.

Related