Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I reuse a &mut reference after passing it to a function that accepts a generic type?

Why doesn't this code compile:

fn use_cursor(cursor: &mut io::Cursor<&mut Vec<u8>>) {
    // do some work
}

fn take_reference(data: &mut Vec<u8>) {
    {
        let mut buf = io::Cursor::new(data);

        use_cursor(&mut buf);
    }

    data.len();
}

fn produce_data() {
    let mut data = Vec::new();
    take_reference(&mut data);
    data.len();
}

The error in this case is:

error[E0382]: use of moved value: `*data`
  --> src/main.rs:14:5
   |
9  |         let mut buf = io::Cursor::new(data);
   |                                       ---- value moved here
...
14 |     data.len();
   |     ^^^^ value used here after move
   |
   = note: move occurs because `data` has type `&mut std::vec::Vec<u8>`, which does not implement the `Copy` trait

The signature of io::Cursor::new is such that it takes ownership of its argument. In this case, the argument is a mutable reference to a Vec.

pub fn new(inner: T) -> Cursor<T>

It sort of makes sense to me; because Cursor::new takes ownership of its argument (and not a reference) we can't use that value later on. At the same time it doesn't make sense: we essentially only pass a mutable reference and the cursor goes out of scope afterwards anyway. In the produce_data function we also pass a mutable reference to take_reference, and it doesn't produce a error when trying to use data again, unlike inside take_reference.

I found it possible to 'reclaim' the reference by using Cursor.into_inner(), but it feels a bit weird to do it manually, since in normal use-cases the borrow-checker is perfectly capable of doing it itself.

Is there a nicer solution to this problem than using .into_inner()? Maybe there's something else I don't understand about the borrow-checker?

like image 829
Samuel Moriarty Avatar asked Jan 08 '18 03:01

Samuel Moriarty


People also ask

How long can you reuse KN95?

Mask Rotation Rotate and use a different KN95 mask every day so you do not wear the same mask more than once every 72 hours. Note: If following this rotation, KN95 masks may be reused as long as they do not become wet, visibly soiled or deformed, causing them to not fit well anymore.

Can I reuse my mask?

A: The CDC recommends reusable face masks be washed after each use and provides information on the washing of cloth face masks. The reuse of barrier face coverings should be determined based upon the manufacturer's instructions, which may include washing and subsequent wear.

How many times can you use an N95?

CDC recommends limiting the number of donnings for an N95 FFR to no more than five per device. It may be possible to don some models of FFRs more than five times [2]. Fit performance during limited reuse should be monitored by the respiratory protection program manager or appropriate safety personnel.

Can you reuse FFP2?

If you want to reuse your FFP2 masks, you can hang them out to dry (in the meantime, please wear another mask when spending time in public spaces). After seven days, the amount of infectious coronavirus on a mask has decreased to an acceptable level, such that it can once again be reused after that period.


1 Answers

Normally, when you pass a mutable reference to a function, the compiler implicitly performs a reborrow. This produces a new borrow with a shorter lifetime.

When the parameter is generic (and is not of the form &mut T), the compiler doesn't do this reborrowing automatically1. However, you can do it manually by dereferencing your existing mutable reference and then referencing it again:

fn take_reference(data: &mut Vec<u8>) {
    {
        let mut buf = io::Cursor::new(&mut *data);

        use_cursor(&mut buf);
    }

    data.len();
}

1 — This is because the current compiler architecture only allows a chance to do a coercion if both the source and target types are known at the coercion site.

like image 68
Francis Gagné Avatar answered Oct 19 '22 22:10

Francis Gagné