Self-referential struct in safe rust

Technically, foo.b points at foo.a.

struct Foo {
  a: i32,
  b: Option<&'static mut i32>,
}

let foo = Box::leak(Box::new(Foo { a: 42, b: None }));
let a = &mut foo.a;
let b = foo.b.get_or_insert(a);

(It is rather a joke)

1 Like

You don't need to use Box::leak for this:

struct Foo<'a> {
    a: i32,
    b: Option<&'a mut i32>,
}
// Foo can't implement Drop:
//impl Drop for Foo<'_> {fn drop(&mut self) {}}

let mut foo = Foo { a: 42, b: None };
// This will borrow `foo.a` for the lifetime of `foo`
foo.b = Some(&mut foo.a);

println!("{:?}", foo.b);

// Can't access `foo.a` again:
// println!("{:?}", foo.a);

(playground)

Yep, they're possible, just sort of useless. This is a little less restrictive. I don't think I've seen a practical example of either though. The examples I have seen are handled just as well by keeping the structs separate, since the self-referential version gets pinned to the stack anyway.

Edit: Not really true, see next comment

I also like this variation:

impl<'a> Snek<'a> {
    fn bite(&'a mut self) -> &'a Self {
        self.borrowed = &self.owned;
        self
    }
}

Because it requires so many lifetime mechanics like borrow splitting for the assignment and shared reborrowing to be able to return &*self.

The invariant case is pretty practical, because the example of typed-arena usage falls under this, and that's not uncommon - e. g. rustc itself is full of this.

E. g.

Note that the lifetime is indeed invariant here (from the invariance of T in TypedArena<T>).

2 Likes

Yeah, true.

Ma beloved useless self-ref static statics.

#[derive(Debug)]
struct Foo(&'static Foo);

static FOO: Foo = Foo(&FOO);
2 Likes