5
votes

I want to have a function foo taking an instance of a type which implements a trait A. I always prefer to use generics in order to have static dispatch:

trait A {}

fn foo<T: A>(t: T) {}

However, this approach introduces some inflexibility, I can't pass a trait object like here:

trait A {}

fn foo(t: &A) {}

The thing is, sometimes I know the type and sometimes not. Is there a way to have both dynamic dispatch for trait objects and static dispatch for compile time known types while not implementing things twice?

1

1 Answers

6
votes

That is indeed possible. One option is to explicitly implement A for its reference types:

impl<'a, T: A + ?Sized> A for &'a T {}

The argument becomes a trait object when T = &A, while still doing static dispatch for known implementors of A. The following code should now compile:

fn foo<T: A>(a: T) {}

struct MyA;
impl A for MyA {}

fn main() {
    foo(MyA{});
    foo(&MyA{});
    foo(&MyA{} as &A);
}

If you are willing to always pass a borrowed argument, you can also do this instead:

fn foo<T: A + ?Sized>(a: &T) {}

The argument becomes a trait object when T = A.