&mut self borrows nested struct from generic type

⚓ Rust    📅 2025-10-02    👤 surdeus    👁️ 6      

surdeus

I am trying to force the user to use a type specified during construction as an argument for &mut self method. The method takes the argument by reference, not value, so the nested values shouldn't be borrowed by the object. It seems that if the method has explicit generic type from struct it borrows nested value but if it has method defined generic type - it is ok (or wrong when the new generic type is limited to the struct generic type).

I am looking for some Rust rules for this behavior, but I can't find anything in documentation. Do you have any explanation for this behavior? Is there any other way to force using the type specified during construction?

This is my code snippet:

use std::marker::PhantomData;

struct A<T> { _t: PhantomData<T> }
impl<T> A<T> {
    fn new() -> A<T> { Self { _t: PhantomData, } }
    fn dummy(&self) { }
    fn handle_a(&mut self, _t: &T) -> Option<()> { None }
    fn handle_b<TT>(&mut self, _t: &TT) -> Option<()> { None }
    fn handle_c<TT: Same<T>>(&mut self, _t: &TT) -> Option<()> { None }
}

pub fn main() {
    struct B<'a>(&'a [u8]);
    let mut a: A<B<'_>> = A::new();

    let data = vec![3; 10];
    let b = B(&data);
    a.handle_a(&b);
    drop(b);
    drop(data);
    a.dummy();

    let data = vec![3; 10];
    let b = B(&data);
    a.handle_b(&b);
    drop(b);
    drop(data);
    a.dummy();

    let data = vec![3; 10];
    let b = B(&data);
    a.handle_c(&b);
    drop(b);
    drop(data);
    a.dummy();
}

pub trait Same<T> {}
impl<T> Same<T> for T {}

And this is the compiler output:

error[E0505]: cannot move out of `data` because it is borrowed
  --> src/main.rs:20:10
   |
16 |     let data = vec![3; 10];
   |         ---- binding `data` declared here
17 |     let b = B(&data);
   |               ----- borrow of `data` occurs here
...
20 |     drop(data);
   |          ^^^^ move out of `data` occurs here
21 |     a.dummy();
   |     - borrow later used here
   |
help: consider cloning the value if the performance cost is acceptable
   |
17 |     let b = B(&data.clone());
   |                    ++++++++

error[E0505]: cannot move out of `data` because it is borrowed
  --> src/main.rs:34:10
   |
30 |     let data = vec![3; 10];
   |         ---- binding `data` declared here
31 |     let b = B(&data);
   |               ----- borrow of `data` occurs here
...
34 |     drop(data);
   |          ^^^^ move out of `data` occurs here
35 |     a.dummy();
   |     - borrow later used here
   |
help: consider cloning the value if the performance cost is acceptable
   |
31 |     let b = B(&data.clone());
   |                    ++++++++

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

This is a link to playground: Rust Playground

2 posts - 2 participants

Read full topic

🏷️ Rust_feed