Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement function for trait implementor with dynamic and static dispatch

Tags:

generics

rust

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?

like image 290
torkleyy Avatar asked Jan 23 '17 17:01

torkleyy


1 Answers

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.

like image 141
E_net4 stands with Ukraine Avatar answered Sep 26 '22 15:09

E_net4 stands with Ukraine