7

This code compiles in C++:

int x = 5;
int *const px = &x;
int *const *const ppx = &px;
int const *const *const cppx = ppx;

So I tried to do the equivalent in Rust:

let mut x: i32 = 5;
let px: &mut i32 = &mut x;
let ppx: &&mut i32 = &px;
let cppx: &&i32 = ppx;

However, this fails to compile:

error[E0308]: mismatched types
 --> src/main.rs:5:23
  |
5 |     let cppx: &&i32 = ppx;
  |               -----   ^^^ types differ in mutability
  |               |
  |               expected due to this
  |
  = note: expected reference `&&i32`
             found reference `&&mut i32`

Why isn't it allowed?

kmdreko
  • 42,554
  • 6
  • 57
  • 106
vbstb
  • 1,261
  • 1
  • 10
  • 14
  • or if you really want it like the C code I don't think that's allowed as that would be a mutable and constant reference to the same object – Zan Lynx Mar 13 '21 at 03:31

1 Answers1

2

So I tried to do the equivalent in Rust:

Careful! C pointers and C++ references are not equivalent to Rust references.

  • int const *x; in C and C++ is a pointer that cannot modify the pointed value. It says nothing about whether the actual value behind the pointer is immutable or not: it is not a pointer to an immutable value! Converting an int *x into that one only restricts what the pointer can do, so it is allowed without a cast. The opposite is not true.

  • &mut i32 in Rust is a mutable reference. If you have one of these, then Rust guarantees that this is the only one that may access the value at this point in time, and that the value itself is mutable. To get such a mutable reference, you had to borrow it at some point. We can convert one of these into an immutable one &i32 because we know we were the only ones, so it is OK to have one immutable one. The opposite is not allowed.

They are similar, and under the hood they end up being an address in memory, but they represent different concepts that give different guarantees.

Why isn't it allowed?

It is, because you are going from mutable to immutable, but you need to be explicit by reborrowing:

let cppx: &&i32 = &&**ppx;

See What's the difference between placing “mut” before a variable name and after the “:”? and https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more information. Rust also has pointer types: *const and *mut.

Acorn
  • 24,970
  • 5
  • 40
  • 69