2

I have the following rust snippet:

trait Foo { 
    fn foo(&self); 
}

struct FooImpl;

impl Foo for FooImpl { 
    fn foo(&self) {} 
}

fn do_foo(foo_doer: impl Foo) { 
    foo_doer.foo()
}

this line works:

do_foo(FooImpl {});

but when I try to run this:

do_foo(&FooImpl {});

I understandably get error: the trait bound &FooImpl: Foo is not satisfied.

I can obviously do this:

impl Foo for &FooImpl { fn foo(&self) {} }

and then it will work, but I'd have to do this for multiple types and I'd have to copy some code each time. Additionally in my case I can only get not only a borrow but a mutable borrow. Which means I have to impl it for &mut FooImpl, and sometimes I'd like to run it from an immutable borrow of the mutable borrow meaning I have to implement it for &&mut FooImpl, you get the idea.

My question is whether there is some trait impl / generic trickery you can recommend that will allow me to impl a trait for both owned instances and borrowed instances?

Alternatively can I change something on the do_foo function side that will allow it to accept both types of instances?

I have read Do I have to implement a trait twice when implementing it for both reference and non-reference types? and it works on my toy program. But my problem is the trait I am trying to impl in my actual code is from a different crate, so the compiler does will not allow me to impl Borrow<FooImpl> on that trait I think due to orphan rules (error: type parameter B must be used as the type parameter for some local type). Is there a solution that works around the orphan rules?

vallentin
  • 23,478
  • 6
  • 59
  • 81
Assaf
  • 1,352
  • 10
  • 19
  • 2
    Define a macro and use that to generate your impls? – eggyal May 11 '20 at 11:49
  • Applying Shepmaster's answer to the other question here: `impl Foo for &'_ F where F: Foo {...}` will cover all your bases with regard to `&` references, and you can do the same for `&mut` references if you like. The `?Sized` bound is not strictly necessary, but lets you use the reference implementation for references to trait objects. – trent May 11 '20 at 11:59
  • 1
    Also read [When should I not implement a trait for references to implementors of that trait?](https://stackoverflow.com/q/28799372/3650362) which explains why additional `impl`s are necessary. – trent May 11 '20 at 12:01
  • @trentcl thank you, but my trait is in a different crate, forgot to mention it, see my edit. Also the second link was enlightening so thanks for that as well. – Assaf May 11 '20 at 12:23
  • 1
    If it's in a different crate, either the crate itself should supply this `impl`, or there is something special about `FooImpl` that makes references to it special in that they can implement `Foo` although in general references to other types that implement `Foo` cannot. There is no general workaround (other than using a macro, as eggyal suggested) hat I know of, but there may be one for your specific case; unfortunately, the question does not contain enough information to suggest one. – trent May 11 '20 at 12:30

1 Answers1

0

My question is whether there is some trait impl / generic trickery you can recommend that will allow me to impl a trait for both owned instances and borrowed instances?

You might be able to use Borrow/AsRef.

sometimes I'd like to run it from an immutable borrow of the mutable borrow meaning I have to implement it for &&mut FooImpl, you get the idea.

Just reborrow to get either an &FooImpl?

Masklinn
  • 34,759
  • 3
  • 38
  • 57