1

So I have a struct looking like this:

struct InterpolationList<'a, T: Interpolatable<T, Output=T>> {,
    first_entry: InterpolationListValue<'a, T>,
    last_entry: &'a mut InterpolationListValue<'a, T>,
}

And now I implemented a new function to create a simple "Instance":

pub fn new(distance: u64, value: T) -> InterpolationList<'a, T> {
    let mut initial_entry = InterpolationListValue::new(distance, value);

    InterpolationList {
        first_entry: initial_entry,
        last_entry: &mut initial_entry,
    }
}

This however gives me the following errors:
cannot return value referencing local variable `initial_entry`
/         InterpolationList {
20 | |             first_entry: initial_entry,
21 | |             last_entry: &mut initial_entry,
   | |                         ------------------ `initial_entry` is borrowed here
23 | |         }
   | |_________^ returns a value referencing data owned by the current function
borrow of moved value: `initial_entry`  
   |  
17 |         let mut initial_entry = InterpolationListValue::new(distance, value);  
   |             ----------------- move occurs because `initial_entry` has type `InterpolationListValue<'_, T>`, which does not implement the `Copy` trait
...
23 |             first_entry: initial_entry,  
   |                          ------------- value moved here   
24 |             last_entry: &mut initial_entry,   
   |                         ^^^^^^^^^^^^^^^^^^ value borrowed here after move

My guess is that rust thinks, ownership of initial_entry still belongs to the function, even though it is moved to the InterpolationList struct, because both move and referencing happens in the same instruction.

Does anybody know how to fix/circumvent this?

Timer ErTim
  • 85
  • 2
  • 10
  • 1
    So the answer is basically: Don't have the reference? – Timer ErTim May 30 '22 at 08:54
  • yes, also makes no sense if you already have the owned version, why would you need the mut reference? – Netwave May 30 '22 at 08:56
  • Because I'm trying to create a linked list like structure, which provides very specific operations. These operations benefit to have direct access to the last element. It's just the initial/new "state" in which last_entry refers to first_entry. – Timer ErTim May 30 '22 at 09:07
  • 1
    In that case, here's some mandatory reading matter: https://rust-unofficial.github.io/too-many-lists/ – Jmb May 30 '22 at 09:10
  • You have to understand that in Rust everything is movable via simple memcpy. This is a very basic fundamental property of Rust that makes things very performant. But that means no pointers/references to objects can exist when a move happens, otherwise they would point to the wrong address. Rust ensures this via the borrow checker, and that's why Rust doesn't allow storing references to members: It would make the struct immovable. There *are* ways to achieve that, but it will involve raw pointers and `Pin`. – Finomnis May 30 '22 at 10:30
  • @Finomnis Linked lists do not need `Pin` if the pointers are kept internal-only. However, you don't need linked lists (probably). – Chayim Friedman May 30 '22 at 20:31
  • @ChayimFriedman You are correct, you could solve linked lists with `Weak`. – Finomnis May 30 '22 at 20:38
  • @Finomnis No, I meant even when you use raw pointer, as `Pin` is only necessary for external APIs and linked lists often do not expose the pointers. For example, [`std::collections::LinkedList`](https://doc.rust-lang.org/stable/src/alloc/collections/linked_list.rs.html#50-55) does not use `Pin`. – Chayim Friedman May 30 '22 at 20:39
  • @ChayimFriedman Well, if you use raw pointers, and manually allocate your own memory for the elements, of course. But "you could use unsafe" probably isn't the answer OP wanted to hear. – Finomnis May 30 '22 at 20:40
  • @Finomnis Sure. All I wanted is that since you mentioned `Pin`, I wanted to say that `Pin` is often not relevant for linked lists. – Chayim Friedman May 30 '22 at 20:44
  • I agree. The mose fitting answer for a linked list specific question would probably be the too-many-lists link. I just wanted to add some general explanation why this is a problem in the first place. – Finomnis May 30 '22 at 20:47

1 Answers1

0

It has been explained several times why.

In this case if I am not missing something from the context, you could just make a method on your struct to access that:

impl<'a, T> InterpolationList<'a, T> where T: Interpolatable<T, Output=T> {
    pub fn last_entry_mut(&mut self) -> &mut InterpolationListValue<'a, T> {
        &mut self.first_entry
    }
}
Netwave
  • 40,134
  • 6
  • 50
  • 93