Answer

There is **no safe way** to create self-referential structs in Rust without `unsafe` or a helper crate. This is by design — the borrow checker cannot express "this field borrows from that field" because moves would invalidate the pointer. **Why `Pin` doesn't solve it alone:** `Pin` prevents the *consumer* from moving the value, but it doesn't help the compiler understand the self-referential borrow. You still need `unsafe` to create and dereference the raw pointer. **Practical options, ranked:** 1. **`ouroboros` crate (recommended):** ```rust use ouroboros::self_referencing; #[self_referencing] struct MyStruct { data: String, #[borrows(data)] #[covariant] slice: &'this str, } ``` Generates safe accessors backed by `unsafe` internally. Battle-tested, widely used. 2. **`self_cell` crate:** ```rust use self_cell::self_cell; self_cell! { struct MyStruct { owner: String, #[covariant] dependent: Slice, } } type Slice = &'a str; ``` Simpler API than ouroboros, slightly less flexible. 3. **Redesign to avoid self-reference:** - Store an index instead of a reference: `ptr: usize` indexing into `data` - Split into two structs with explicit lifetime: `struct View { data: &'a String }` - Use `Rc` so both "fields" share ownership without borrowing 4. **Manual `unsafe` with `Pin`:** ```rust impl SelfRef { fn new(data: String) -> Pin> { let mut boxed = Box::pin(SelfRef { data, ptr: std::ptr::null(), _pin: PhantomPinned }); let ptr = &boxed.data as *const String; unsafe { boxed.as_mut().get_unchecked_mut().ptr = ptr; } boxed } } ``` Works but you own the `unsafe` — any future refactoring that moves the struct is UB. **Bottom line:** Use `ouroboros` or redesign to avoid the self-reference entirely. The index-based approach (option 3) is often the simplest and most Rust-idiomatic solution.

fe22ac4f-ba20-4ba8-9b32-0640aada50f4

There is no safe way to create self-referential structs in Rust without unsafe or a helper crate. This is by design — the borrow checker cannot express "this field borrows from that field" because moves would invalidate the pointer.

Why Pin doesn't solve it alone: Pin prevents the consumer from moving the value, but it doesn't help the compiler understand the self-referential borrow. You still need unsafe to create and dereference the raw pointer.

Practical options, ranked:

  1. ouroboros crate (recommended):
use ouroboros::self_referencing;

#[self_referencing]
struct MyStruct {
    data: String,
    #[borrows(data)]
    #[covariant]
    slice: &'this str,
}

Generates safe accessors backed by unsafe internally. Battle-tested, widely used.

  1. self_cell crate:
use self_cell::self_cell;

self_cell! {
    struct MyStruct {
        owner: String,
        #[covariant]
        dependent: Slice,
    }
}
type Slice = &'a str;

Simpler API than ouroboros, slightly less flexible.

  1. Redesign to avoid self-reference:

    • Store an index instead of a reference: ptr: usize indexing into data
    • Split into two structs with explicit lifetime: struct View { data: &'a String }
    • Use Rc so both "fields" share ownership without borrowing
  2. Manual unsafe with Pin:

impl SelfRef {
    fn new(data: String) -> Pin> {
        let mut boxed = Box::pin(SelfRef { data, ptr: std::ptr::null(), _pin: PhantomPinned });
        let ptr = &boxed.data as *const String;
        unsafe { boxed.as_mut().get_unchecked_mut().ptr = ptr; }
        boxed
    }
}

Works but you own the unsafe — any future refactoring that moves the struct is UB.

Bottom line: Use ouroboros or redesign to avoid the self-reference entirely. The index-based approach (option 3) is often the simplest and most Rust-idiomatic solution.