0

I am trying to implement a Directed Acyclic Graph in Rust, and have two structs defined like this:

struct ValueData {
    val: BaseType,
    children: Vec<Rc<RefCell<Value>>>,
    name: &'static str,
}

pub struct Value(Rc<RefCell<ValueData>>);

Given a variable of type Value, I want to be able to get its members like so:

impl Value {
   fn name(&self) -> &'static str {
        (*(self.0)).borrow().name
    }

    fn val(&self) -> BaseType {
        (*(self.0)).borrow().val
    }

    fn children(&self) -> Vec<Rc<RefCell<Value>>> {
        (*(self.0)).borrow().children
    }
}

In this code example, the methods name and val compile properly, but children doesn't with the following error:

error[E0507]: cannot move out of dereference of `Ref<'_, ValueData>`
  --> src\grad.rs:61:9
   |
61 |         (*(self.0)).borrow().children
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec<Rc<RefCell<Value>>>`, which does not implement the `Copy` trait

If I change it to the following:

    fn children(&self) -> &Vec<Rc<RefCell<Value>>> {
        &(*(self.0)).borrow().children
    }

I then get an error:

error[E0515]: cannot return value referencing temporary value
  --> src\grad.rs:61:9
   |
61 |         &(*(self.0)).borrow().children
   |         ^--------------------^^^^^^^^^
   |         ||
   |         |temporary value created here
   |         returns a value referencing data owned by the current function

Which makes it seems as if the Vector is being cloned upon accessing it (if not, what is the "temporary value" that the compiler is complaining about?).

How do I get the pointer to the Vector that already exists inside the ValueData struct from the Value struct? I don't want the vector to get copied, neither do I want to modify the vector or its contents -- all I want is a read-only reference so that I can print its contents recursively.

EDIT after getting marked duplicate: The answers to the linked question don't seem to be answering my question, since they are about acquiring a Ref<T> while I want to be able to return &T (that is, simply the pointer to the vector without any encapsulation). The only thing I can find in the leak method, but it is marked nightly-only.

ndsrib
  • 3
  • 2
  • Usually refCell is used to mutate data behind an immutable reference, if you don't need mutability on the children I'm just curious why you chose to go with refCell instead of a straight vec of values. In regards to your question, the reason the compiler is complaining is because you're creating a temporary value by calling `self.0.borrow()` and then returning a ref to it's children. After the function returns the temp value doesn't exist so the reference won't be valid. Instead of returning a reference, return a clone of the children: `self.0.borrow().children.clone()` – wade king Aug 01 '23 at 17:52
  • If you want to do it without cloning, you'll have to deal with lifetimes and get rid of the refcell in the value struct: `pub struct Value(ValueData);` fn children<'a>(&'a self) -> &'a Vec>> { &self.0.children } Basically this reassures the rust compiler that the reference to self's children lasts as long as self does, so the reference won't be null – wade king Aug 01 '23 at 18:01
  • @wadeking So, I need to be able to store multiple immutable references to each node (`Value`) in multiple different nodes. Additionally, I also need to allocate `Value` on heap so that it's identity remains constant. When I tried to do this with `Box`, I was getting way too many warnings about value being moved. Trying to debug this, I found [this](https://github.com/nrc/r4cppp/blob/master/graphs/README.md) that used `Rc>`. If I am doing it wrong, or making it to complex, please let me know. I am new to Rust, and most of my experience has been in C. – ndsrib Aug 02 '23 at 06:45
  • @wadeking Okay, with your suggestions, I removed `RefCell` and made it work with `Rc` only (since the data remains immutable after creation anyway). Thank you for the answer :) – ndsrib Aug 02 '23 at 07:22

0 Answers0