0

Commonly, a program object will contain a list of objects that reference a shared property in the container object.

Rust, without using a heap allocated reference counter or similar, prevents multiple owners to the same reference.

Example

The following code demonstrates an example pattern commonly encountered in the wild:

#[derive(Debug)]
struct Identity {
    token: String,
}

#[derive(Debug)]
struct Service<'a> {
    identity: &'a Identity,
    uri: String,
}

impl<'a> Service<'a> {
    pub fn new(identity: &'a Identity, uri: String) -> Self {
        Service { identity, uri }
    }
}

#[derive(Debug)]
struct Services<'a> {
    identity: Identity,
    services: Vec<Service<'a>>,
}

impl<'a> Services<'a> {
    pub fn new() -> Self {
        Services {
            identity: Identity {
                token: String::new(),
            },
            services: Vec::new(),
        }
    }

    pub fn add_service(&'a mut self, uri: String) {
        self.services.push(Service {
            identity: &self.identity,
            uri,
        });
    }
}

fn main() {
    let mut services = Services::new();
    services.add_service(String::from("https://api.stackexchange.com"));
    services.add_service(String::from("https://api.stackoverflow.com"));
    println!("{:?}", services);
}

Output

error[E0499]: cannot borrow `services` as mutable more than once at a time
  --> src/main.rs:45:5
   |
44 |     services.add_service(String::from("https://api.stackexchange.com"));
   |     -------- first mutable borrow occurs here
45 |     services.add_service(String::from("https://api.stackoverflow.com"));
   |     ^^^^^^^^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

error[E0502]: cannot borrow `services` as immutable because it is also borrowed as mutable
  --> src/main.rs:46:22
   |
44 |     services.add_service(String::from("https://api.stackexchange.com"));
   |     -------- mutable borrow occurs here
45 |     services.add_service(String::from("https://api.stackoverflow.com"));
46 |     println!("{:?}", services);
   |                      ^^^^^^^^
   |                      |
   |                      immutable borrow occurs here
   |                      mutable borrow later used here

Question

How can you create this pattern in Rust with the expectation that the Services vector will be updated within a GUI REPL loop?

10
  • 2
    TL;DR the duplicate — you don't, generally. Use an Rc or an Arc (like all the languages where this is a common pattern effectively do); pass in the reference instead of self-referencing; or in very rare cases, use unsafe code and prove that the code is safe. Your case is not memory safe, so I would not recommend it. Commented Dec 1, 2020 at 18:01
  • "pass in the reference instead of self-referencing", not sure what this means or how to implement this... the use-case for me was to create an adapter and trait for a type of network connection involving devices but to abstract the specific implementation details away since the library I'm using makes its own decisions about how to manage the session and use that for each device. it seems like the prescribed solution is always punt these objects up to main func to establish a global scope that lacks generic application... Commented Dec 1, 2020 at 19:00
  • also, looking at the example in the link provided... the reference to parent is made then parent is moved, I don't think my example does that. when a new service is added it takes a reference to the identity already existing on the Services struct which has a lifetime as long as any field it contains Commented Dec 1, 2020 at 19:07
  • 1
    Your example code is actually closer to the section in the answer titled "A type with a reference to itself". Commented Dec 1, 2020 at 19:33
  • 1
    the crate im using requires its own session and adapter object — yes, and that's a design issue with the library, unfortunately. See also How to store rusqlite Connection and Statement objects in the same struct in Rust?; How to store SQLite prepared statements for later?. Some libraries provide owned and reference versions, others have caching mechanisms, others have very lightweight structs that you can create over and over without saving them, etc. Commented Dec 1, 2020 at 19:41

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.