-1

I'm new to Rust and for the first time I'm writing this sort of code:

PLAYGROUND HERE

#[tokio::main]
async fn main() {
    #[derive(Default, Clone)]
    pub struct Coach {
        id: Option<i64>,
        name: String,
        team: Option<Team>
    }

    #[derive(Default, Clone)]
    pub struct Team {
        id: Option<i64>,
        name: String,
        coach: Option<Coach>
    }
}

The error is:

error[E0072]: recursive type `Coach` has infinite size
 --> src/main.rs:4:5
  |
4 |     pub struct Coach {
  |     ^^^^^^^^^^^^^^^^ recursive type has infinite size
...
7 |         team: Option<Team>
  |               ------------ recursive without indirection
  |
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Coach` representable
  |
7 |         team: Option<Box<Team>>
  |                      ++++    +

error[E0072]: recursive type `Team` has infinite size
  --> src/main.rs:11:5
   |
11 |     pub struct Team {
   |     ^^^^^^^^^^^^^^^ recursive type has infinite size
...
14 |         coach: Option<Coach>
   |                ------------- recursive without indirection
   |
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Team` representable
   |
14 |         coach: Option<Box<Coach>>
   |                       ++++     +

For more information about this error, try `rustc --explain E0072`.

Coming from Go where something like this is easily possible, what is Rust idiomatic code?

Fred Hors
  • 3,258
  • 3
  • 25
  • 71
  • The compiler is literally telling you what to do. – Chayim Friedman Oct 19 '22 at 14:48
  • Yeah, but what is the idiomatic way of doing it? Box or lifetimes for example? – Fred Hors Oct 19 '22 at 14:49
  • Just like the compiler is telling you. – Chayim Friedman Oct 19 '22 at 14:49
  • @ChayimFriedman I wouldn't overgeneralize on this, because the compiler does give nonsensical instructions in certain situations. But for this specific case, I'd agree that adding `Box` is the correct way to go. – Finomnis Oct 19 '22 at 18:40
  • @FredHors `Box` and lifetimes are not interchangeable. They are completely separate concepts that don't even go in the same direction. You probably mean references. – Finomnis Oct 19 '22 at 18:41
  • Yeah, as explained in this comment https://stackoverflow.com/questions/25296195/why-are-recursive-struct-types-illegal-in-rust#comment102377335_25296420 I would like to not allocate on the heap... – Fred Hors Oct 19 '22 at 18:43
  • @FredHors Whatever you are trying to achieve with it, I'm 99% sure that you are going the wrong direction. If you really do want this, you probably want weak RC pointers. Everything else is either almost impossible to create, or prone to leaking memory. Remember, Rust does not have a garbage collector like many other languages, Rust explicitly made the decision to not have a runtime. – Finomnis Oct 19 '22 at 18:51
  • @ChayimFriedman Voting to reopen because the linked answer does not say anything about recursive **object** references (object a referencing object b referencing object a), it only states **struct** references (object a referencing object b of the same type). There are solutions to what he is trying to do, like storing the objects as `Rc` somewhere and having them reference each other through `Weak`. – Finomnis Oct 19 '22 at 18:56
  • @Finomnis I don't know what he is trying to do. It may be cyclic data structure or not. – Chayim Friedman Oct 19 '22 at 18:58
  • @ChayimFriedman The names are `coach` and `team`. I'd argue it is very simply to infer that it is a cyclic reference. Which the duplicate question does in fact ask about, but neither answer even mentions it. – Finomnis Oct 19 '22 at 18:59
  • @ChayimFriedman On the other hand, what I just said probably in fact does mean that it is a duplicate. There's just a proper answer missing there. I might add it. – Finomnis Oct 19 '22 at 19:00
  • I'll wait for a correct answer to this @Finomnis because you're right: that answer does not talk about recursive structs. – Fred Hors Oct 19 '22 at 19:45
  • @FredHors Added an answer that talks about `Rc` and `Weak` in [the other question](https://stackoverflow.com/a/74131079/2902833). – Finomnis Oct 19 '22 at 19:49
  • 1
    @FredHors I have to correct your terminology though, the answer does very much talk about recursive structs. It does not talk about cyclic references. There's a fine but important difference between the two. – Finomnis Oct 19 '22 at 19:56

1 Answers1

1

add Box, since it's a "pointer"

#[tokio::main]
async fn main() {
    #[derive(Default, Clone)]
    pub struct Coach {
        id: Option<i64>,
        name: String,
        team: Option<Box<Team>>
    }

    #[derive(Default, Clone)]
    pub struct Team {
        id: Option<i64>,
        name: String,
        coach: Option<Box<Coach>>
    }
}

you could ref to https://rust-unofficial.github.io/too-many-lists/first-layout.html?highlight=box#basic-data-layout

AsukaMinato
  • 1,017
  • 12
  • 21
  • Sotty, I updated the question using the `Option<>`. Can you re-cehck please? – Fred Hors Oct 19 '22 at 14:48
  • 1
    Be aware that while this is possible to define, it doesn't make much sense to use it. Once created it would be impossible to use. You will never be able to create a `Coach` who owns his `Team` which owns him back. Creating such objects would force you to drop all references to them, essentially leaking them. – Finomnis Oct 19 '22 at 18:45
  • @Finomnis can I ask you what do you suggest? – Fred Hors Dec 19 '22 at 22:05
  • @FredHors If you want to pursuit the path you are on, a combination of `Rc`, `Weak` and `RefCell`. But I'd argue that it would be better to lay out your data structures in a way so this isn't required. But that probably depends on the exact problem you have. – Finomnis Dec 19 '22 at 22:31
  • @Finomnis yeah, this is what I'm trying to understand: how to lay out my data structures. Can you point me in a direction, please? Something like CRUD with multiple (nested) entities... – Fred Hors Dec 19 '22 at 22:33
  • Not sure, I'm missing context here. Maybe create a new question with more detail? Maybe here, or maybe on https://codereview.stackexchange.com/. – Finomnis Dec 21 '22 at 07:22