Is is possible to make nested structs?


#1

Hi sorry if I’m asking something which is not acceptable for Rust ideology, but I’m trying to understand how solve problem.

So I have now 3 structs like this ones

struct Network {
    ......
    ......
    server: Server,
    client: Client
}

struct Server {
    ......
    .....
    net: Network
}

struct Client {
    ......
    .....
    net: Network
}

Basically I’m trying to create Network object which will contain Server object with same Network object and same with Client object.
In C++ and in any other language I’ll just keep pointer to Network object inside Client and Server structs. But how to do this with Rust ?

Thanks for your help


#2

Hi there!

I’m new to Rust, but here’s what I already understand about this issue you’re facing:

For one, structs in Rust need to have a known, finite size at compile-time (I think there is some exception to this, can’t remember what it was, but this is the general rule) – which is impossible for a set of structs which include each other. Struct fields are “inlined”, if that makes sense. (Compiler says something like: recursive type has infinite size)
So you’ll need to at least do something like:

struct Network {
  server: Box<Server>,
  client: Box<Client>
}

and similar for the other structs.

BUT, then comes the real issue here, I think: How do you even create an instance of a struct that contains a pointer (Box) to another struct that contains a pointer back to the first struct? I just tried to type out the code (https://is.gd/Jlkmz3), but my understanding so far suggests that this might not be possible without turning one of the references into Option<Box<Network>> so that you don’t have to set the value at initialization and can instead specify it later?

But again, I’m just learning Rust myself at the moment and thinking about this and typing it out, so this is just a newbie perspective and not necessarily (entirely) correct or complete.


#3

The exception is that the last field can be unsized, in which case, the struct is also unsized.


#4

Fundamentally, you’re turning a tree of structs (Network has a Server and a Client) into a graph of structs (these all point to each other). The Right Way to do this has a number of different answers, then. One way to do it would be to use Rc/Weak. See rc’s docs for an example (the second one) https://doc.rust-lang.org/stable/std/rc/index.html


#5

I’ve tried with Rc but when I’m trying to call some function I’m getting error cannot borrow immutable borrowed content as mutable

struct Network {
    server: Rc<Server>
}

.........
self.server.some_function(); // Getting error here for self.server

For my case using Rc would be ideal solution, but I’m fighting with compiler all day for this.
Can you bring some very simple code example for my case just to understand how to solve this problem.
Thanks


#6

Finally got running now !!
I’ve done with Arc and with function Arc::get_mut https://doc.rust-lang.org/std/sync/struct.Arc.html#method.get_mut
It is very similar to this one

struct Network {
    server: Arc<Server>
}

.........
let mut ss = self.server.clone();
let mut s = Arc::get_mut(&mut ss);  // turning our server object into mutable
s.some_function(); 

Let me know if I’m doing it wrong. Just want to understand if there’s other solutions, because for me it seems “hacking” something :slight_smile:


#7

So, Rc (and Arc) treat their contents as immutable. If you need mutation, you need to combine them with something: Rc with RefCell, Arc with Mutex.

(I don’t have time to make an example right now, maybe someone else does :slight_smile: )