impl trait
impl Trait
can appear in two places:
- argument position: anonymous type paramater
- return position : abstract return type
trait Trait {}
fn foo(arg : impl Trait) { }
fn bar() -> impl Trait { }
Generic type paramater vs impl Trait
trait Trait {}
fn foo_generic<T: Trait>(arg : T) { }
fn foo_impl(arg : impl Trait) { }
foo_generic
can do likefoo_generic::<i32>(1)
butfoo_impl
can't
#![allow(unused)] fn main() { fn bar_generic<T: Trait> -> T { } fn bar_impl() -> impl Trait { } }
bar_generic
allows the caller to determine the return typeT
, butbar_impl
won't
impl Trait in return position
// instead of this
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box:new(|x| x + 1)
}
// we can do this with impl trait to avoid heap allocation and dynmic dispatch
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
Limitations
impl Trait
can appear in a free or inherent function
- as a paramater
- as a return type
It can't appear
- inside implementation of traits
- let binding
- inside a type alias
&impl Trait
#![recursion_limit="1000"] use std::fmt::Display; enum Node<T> { Leaf(T), Children(Vec<Node<T>>), } impl<T: Display> Node<T> { fn traverse(&self, f: &impl Fn(&T)) { match self { Node::Leaf(x) => f(x), Node::Children(children) => { for n in children { n.traverse(f); } } } } } fn main() { let tree = Node::Children(vec![ Node::Leaf(1), Node::Children(vec![Node::Leaf(2), Node::Leaf(3), Node::Leaf(4)]), ]); tree.traverse(&|x| println!("{x}")) }