# How to make a struct which handle a self-referential type ? (it's more complicate than that))

I apologize for the title which is not very clear, but I don't know how to describe my problem.
I try to make a program that do some dimensional analysis.
What I do is that a make a tree for the dimensions (a unit like “kg”, a power like “m²”, or a calculation like “U × I”).
Then I want to have my dimension with only the ones from the SI.
For now, it was quite simple to implement this.

But now I want to stock the dimension and its SI representation in a same struct.

So first, we have an enum Dimension<'a> which is a tree that represent a calculation.

``````pub enum Dimension<'di> {
Unite(String),
Power(&'di RawDimension<'di>, i32),
Composed(&'di Dimension<'di>, Op, &'di Dimension<'di>),
}

enum Op {
Plus,
Minus
}
``````

Add, a method to get the SI representation

``````impl<'di> Dimension<'di> {
fn into_SI(&'di self) -> Vec<Dimension> {
// some code
vec![]
}
}
``````

Finally, we have a struct Final<'a> which handle a Dimension<'a> add its result.

``````struct Final<'di> {
dimension: Dimension<'di>,
SI: Vec<Dimention<'di>>
}
``````

BUT, when the time comes to initialize Final, everything goes wrong.

``````impl<'di> From<Dimension<'di>> for Final<'di> {
fn from(dim: Dimension<'di>) -> Final<'di> {
Final {
dimension: dim,   // dim is owned by the dimention field
SI: dim.into_SI(), // but it's borrow here at the same time !
}
}
}
``````

I try to use Pin, but I don't manage to make it work.
Do you have any solution ?

This looks like the sort of problem where one should not use references, but ownership. Most tree data structures should not use references (and this is like an expression tree).

Use `Box<Dimension>` instead of `&'di Dimension<'di>`. Once you do that, the struct `Dimension` will no longer need to have any lifetime parameter, because it owns its “child nodes” and so they always live long enough by definition.

If you expect to have repeated subtrees (e.g. if a unit is already SI so there is no different non-SI version) then use `Rc<Dimension>` instead of `Box<Dimension>`, to allow sharing one copy.

3 Likes

BTW, Rust's naming conventions use `into` for methods that destroy the original by taking `fn into(self)` (not borrow). You have `.to_SI()`.

But it is a self-referential struct, and it can't work. `Pin` won't help.

`Pin` doesn't enable making self-referential structs. It's more like a type-system warning about self-referential structs that already exist. But user code can't make such structs, only the Rust compiler can, and only as a hidden implementation detail of `async` code.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.