You are trying to define a self-referential struct.
Basically you are trying to define:
struct A<'a> {
self_ref: Option<&'a Self>,
}
impl<'a> A<'a> {
fn new () -> Self
{
Self { self_ref: None }
}
fn add (self: &'_ mut Self)
{
self.self_ref = Some(self);
}
}
which leads to your error: Playground.
Solution
Generally, this is a bad pattern in Rust, which ought to be solved by refactoring your struct into split borrows.
For your closure, for instance, you could have:
struct A {
f: Box<dyn Fn(&'_ Self)>, // give self as parameter rather than a capture
}
impl A {
fn new () -> Self
{
Self { f: Box::new(|_| {}) } // btw, no need to prefix the closure with `&`
}
fn add (self: &'_ mut Self)
{
self.f = Box::new(|this| this.show());
}
fn show (self: &'_ Self)
{}
}
and then use it as (self.f)(&self)
.
- If you want some sugar, you can define
fn f(&self) { (self.f)(self) }
and then you can just do self.f()
Other solutions (forcing the self-referential pattern)
One is to solve the mismatch in lifetimes by replacing the elided lifetime '_
in fn add (self: &'_ mut A<'a>)
by the lifetime 'a
carried by the struct (and replace mut
with interior mutability). This will make this code compile, but it will restrict the lifetime of the borrow so much at call site that your struct will be unusable: it is the code using it that will likely fail to compile!
The other option is to stop using compile-time-checked references (since the acyclic graph nature of its analysis does not deal well with self-references since that's, well, a cycle), and use runtime checked references, such as Rc
:
use ::std::{
cell::Cell,
rc::{self, Rc},
};
struct A {
self_ref: Cell<Option< RcA >>,
}
#[derive(Clone)]
struct RcA /* = */ (
Rc<A>,
);
impl RcA {
fn new () -> Self
{
Self(Rc::new(
A { self_ref: Cell::new(None) }
))
}
fn add (self: &'_ Self)
{
self.0.self_ref.set(Some(
self.clone()
));
}
}
This compiles and works fine, BUT:
it leaks memory
Indeed, we have created an Rc
cycle (yep, cycles are annoying even for some runtime constructs).
Luckily, we can remove the cyclic relationship by introducing a hierarchy between the references: the "back ref" (self_ref
) should not own the A
it points to. This can be expressed with the rc::Weak
reference type:
use ::std::{
cell::Cell,
rc::{self, Rc},
};
struct A {
self_ref: Cell<Option< rc::Weak<A> >>,
}
#[derive(Clone)]
struct RcA /* = */ (
Rc<A>,
);
impl RcA {
fn new () -> Self
{
Self(Rc::new(
A { self_ref: Cell::new(None) }
))
}
fn add (self: &'_ Self)
{
self.0.self_ref.set(Some(
Rc::downgrade(&self.0)
));
// upgrading self_ref to a RcA on usage is done with:
// `RcA(self.0.self_ref.upgrade().unwrap())`
}
}
Now we can apply this knowledge to your self-referential-through-closure-capture type:
use ::std::{
cell::Cell,
rc::Rc,
};
struct A {
f: Cell< Box<dyn Fn()> >, // idea: it can capture `rc::Weak<A>`
}
#[derive(Clone)]
struct RcA /* = */ (
Rc<A>,
);
impl RcA {
fn new () -> Self
{
Self(Rc::new(
A { f: Cell::new(Box::new(|| println!("new()"))) }
))
}
fn add (self: &'_ Self)
{
let this = Rc::downgrade(&self.0);
self.0.f.set(Box::new(move || {
let this = RcA(this.upgrade().unwrap());
this.show();
}));
}
fn show (self: &'_ Self)
{
println!("Showing!");
}
fn f (self: &'_ Self)
{
let f = self.0.f.replace(Box::new(|| {}));
f();
self.0.f.set(f);
}
}
fn main ()
{
let a = RcA::new();
a.f();
a.add();
a.f();
}
Note: ideally this forced pattern could be made smoother once we are allowed to write: self: &'_ Rc<Self>
receivers, since that would not involve the newtype wrapper (or using a helper trait; those are the two workarounds for &'_ Rc<_>
receivers).