When writing code with traits you can put the trait in a trait bound:
use std::fmt::Debug;
fn myfunction1(v: Box) {
println!(\"
With <T: Trait> Box<T>
you are using a trait bound to tell the compiler that you want a Box
with an instance of some type T
which implements Trait
, and you will specify T
when you use it. The Rust compiler will likely create different, efficient, code for each different T
in your code (monomorphization).
With Box<Trait>
you are telling the compiler that you want a Box
with a trait object, a pointer to an unknown type which implements Trait
, which means that the compiler will use dynamic dispatch.
I've included two examples which makes the difference a bit clearer:
<T: Trait> Box<T>
, i.e. trait bound:
use std::fmt::Debug;
struct Wrapper<T> {
contents: Option<Box<T>>,
}
impl<T: Debug> Wrapper<T> {
fn new() -> Wrapper<T> {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<T>) {
}
}
fn main() {
let mut w = Wrapper::new();
// makes T for w be an integer type, e.g. Box<i64>
w.insert(Box::new(5));
// type error, &str is not an integer type
// w.insert(Box::new("hello"));
}
Box<Trait>
, i.e. trait object:
use std::fmt::Debug;
struct Wrapper {
contents: Option<Box<Debug>>,
}
impl Wrapper {
fn new() -> Wrapper {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<Debug>) {
}
}
fn main() {
let mut w = Wrapper::new();
w.insert(Box::new(5));
w.insert(Box::new("hello"));
}
For further details on the difference between trait bounds and trait objects I recommend the section on trait objects in the first edition of the Rust book.
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.