Basic borrow checker

Hello there,

I feel a bit embarrassed by my apparent lack of understanding of what is probably a very simple borrow checking issue.

I have this playground that mimics a situation I encountered in my project:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0331b2c4008adbb58c79df5ec00472bc

The gist of it is: I have a mutable struct in my main:

let mut spi = Spidev::new()

I can easily pass that for a method call to a local
function via

full_duplex(&mut spi);

with the signature being

fn full_duplex(spi: &mut Spidev)

My understanding according to https://doc.rust-lang.org/1.0.0/book/mutability.html is that the parameter spi is a mutable reference. Which makes sense - we want to work with spi and mutate it, but not rebind the name spi to anything else.

But then I introcude an intermediate function work:

fn work(mut spi: &mut Spidev)
{
    loop {
        full_duplex(&mut spi);
        if spi.counter % 10 == 0 {
            break;
        }
    }
}

And here the mut in front of spi is the culprit. How come I need this? I do not re-bind spi (to the best of my knowledge.

What am I missing? Waiting to slap my head.

You can change this line:

full_duplex(&mut spi);

to this:

full_duplex(spi);

because spi aready has type &mut Spidev. Then you can remove the extra mut.

In the original code, &mut spi creates an &mut &mut Spidev (a mutable reference to a mutable reference). This has the power to mutate the original reference spi, which is why spi has to be mutable. Then deref coercion lets you cast it back to &mut Spidev.

1 Like

This makes so much sense I even tried it at some point but must have somehow bungled it so I didn't follow through. Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.