This is horribly complicated on its surface because of lifetime issues. Rust is designed to guarantee memory safety, but this pattern creates an untenable situation where the caller of FooTrait::open() needs some way to tell Rust that the client borrow will outlive *self. If it can't do that, Rust will disallow the method call. Actually making this work with references is probably not feasible, as Foo needs a lifetime parameter, but the code that creates the Foo may not know the appropriate lifetime parameter.
You can make this pattern work by combining a few things, but only if you can modify the trait. If you can't change the definition of the trait, then what you are asking is impossible.
- You need an
Option so that close can clear the value. - You need interior mutability (a
Cell) to allow mutating self.client even if self is a shared reference. - You need something other than a bare reference. An owned value or a shared ownership type like
Rc or Arc, for example. These types sidestep the lifetime issue entirely. You can make the code generic over Borrow<T> to support them all at once.
use std::cell::Cell; use std::borrow::Borrow; pub trait FooTrait { fn open(&self, client: impl Borrow<SomeType> + 'static); fn close(&self); } pub struct SomeType; pub struct Foo { client: Cell<Option<Box<dyn Borrow<SomeType>>>>, } impl FooTrait for Foo { fn open(&self, client: impl Borrow<SomeType> + 'static) { self.client.set(Some(Box::new(client))); } fn close(&self) { self.client.set(None); } }