Rob Latham
Rob Latham

Reputation: 5223

What is the reason for requiring &mut foo instead of &foo when foo has been declared mutable?

For a C routine like

MPI_Comm_rank(MPI_Comm comm, int *rank);

The Rust foreign function interface could be declared like this:

use libc::c_int; // 0.2.79

#[link(name = "mpi")]
extern "C" {
    fn MPI_Comm_rank(mpi_comm: c_int, rank: *mut c_int);
}

I call the binding like this, which works, but left me puzzled about syntax:

pub static MPI_COMM_WORLD: libc::c_int = 0x44000000;
fn main() {
    let mut rank: c_int = 999999;
    /* but why '&mut rank' and not simply '&rank' ? */
    unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &mut rank) }
}

I originally tried

unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }

but this gives a compiler error:

error[E0308]: mismatched types
  --> src/main.rs:12:44
   |
12 |     unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }
   |                                            ^^^^^ types differ in mutability
   |
   = note: expected raw pointer `*mut i32`
                found reference `&i32`

I declared 'rank' as mut, so what gives?

Upvotes: 3

Views: 3350

Answers (2)

Chris Morgan
Chris Morgan

Reputation: 90742

You’re conflating two completely distinct features.

let mut x; makes a mutable binding x, allowing you to modify what x is bound to (x = 42) and for non-reference types to modify its contents (x.y = 42). It does not control the mutability of the target of references.

This is different from the type of references you’re dealing with.

  • &mut T is a mutable reference and can be coerced to *mut T.

  • &T is an immutable reference can be coerced to *const T.

As the function you are calling wants *mut T, you must pass it a *mut T or a &mut T; *const T or &T will not do.

To be sure, you can only take a mutable reference to mutable data, so let x = 42; &mut x doesn’t work as it needs let mut x instead of let x, but that’s still entirely distinct and is a part of Rust’s rules about mutability.

Upvotes: 8

Vladimir Matveev
Vladimir Matveev

Reputation: 127751

Your function expects *mut c_int pointer (a mutable raw pointer), and you need to use &mut operator to obtain it. However, you can only take &mut pointer to mut variables, hence you need to declare rank variable as mut rank.

If your function expected *const c_int pointer, you would be able to use &, but this is not the case.

Upvotes: 1

Related Questions