Reputation: 259
I know that a Rust reference is much like a C pointer, and I think of Rust references as C pointers all the time. After some experiments and searching, I'm confused.
I'm familiar with C and I've read What's the difference between placing “mut” before a variable name and after the “:”?, which gives the following table:
// Rust C/C++ a: &T == const T* const a; // can't mutate either mut a: &T == const T* a; // can't mutate what is pointed to a: &mut T == T* const a; // can't mutate pointer mut a: &mut T == T* a; // can mutate both
The post is upvoted so I assume that it is correct.
I wrote the following Rust code
fn main() {
let mut x = 10;
let x1 = &mut x;
let x2 = &x1;
let x3 = &x2;
***x3 = 20;
}
in the hope that it is equivalent to the following C code
int main() {
int x = 10;
int *const x1 = &x;
int *const *const x2 = &x1;
int *const *const *const x3 = &x2;
***x3 = 20;
return 0;
}
The Rust code doesn't compile:
error[E0594]: cannot assign to `***x3` which is behind a `&` reference
--> src/main.rs:6:5
|
6 | ***x3 = 20;
| ^^^^^^^^^^ cannot assign
What's wrong here?
Strangely enough, the following code compiles!
fn main() {
let mut x = 10;
let mut x1 = &mut x;
let mut x2 = &mut x1;
let mut x3 = &mut x2;
***x3 = 20;
}
Why should let mut x1/2/3
be used instead of just let x1/2/3
? I think of let x1 = &mut x
as a constant pointer pointing to a mutable variable x
, but it doesn't seem to be right in Rust. Is that Stack Overflow post inaccurate or I misunderstand it?
Upvotes: 5
Views: 1021
Reputation: 30587
There are a few differences between Rust and C which do not show up in the table you have referenced in your question.
In Rust, mutability is a property of the binding rather than of the type.
Rust has strict aliasing rules, such that you cannot have more than one mutable reference to any variable at one time.
Your question (simplified) is: why can't I have a non mutable reference to a mutable variable, and mutate that variable through it. However, if you could do that you could also have two references which could be used to modify the variable, like this:
let mut x = 10;
let x1 = &mut x;
let x2 = &x1; // Non mutable reference to x1, ok
let x3 = &x1; // Another non mutable reference to x1, ok
**x2 = 20; // uhoh, now I can mutate 'x' via two references ... !
**x3 = 30;
Regarding your C equivalent to the given Rust code - you have not translated it according to the table. Consider this:
let x2 = &x1;
From the table in the answer you quoted:
a: &T == const T* const a; // Can't modify either
In this case, T would be const int*
. So, it would be:
const int* const* const x2 = &x1;
Your whole program would be:
int main() {
// let mut x = 10;
int x = 10;
// let x1 = &mut x;
// a: &mut T == T* const a with T=int
int* const x1 = &x;
// let x2 = &x1;
// a: &T == const T* const a with T = int* const
const int* const* const x2 = (const int* const* const) &x1;
// let x3 = &x2;
// a: &T == const T* const a with T = const int* const* const
const const int* const* const* const x3 = &x2;
***x3 = 20;
return 0;
}
Note that a cast is needed to avoid warnings in the assignment of x2. This is an important clue: we are effectively adding const-ness to the pointed to object.
If you try to compile that you get:
t.c: In function ‘main’:
t.c:17:11: error: assignment of read-only location ‘***x3’
***x3 = 20;
^
Upvotes: 6
Reputation: 97
In Rust it's a bit different. The & sign means reference to something and the * sign means dereference something. If my memory serves me correct, the C/C++ syntax makes use of the '->' symbol (Which is a way of dereferencing), which doesn't appear in Rust.
The hard part in Rust is keeping track of what's being borrowed by whom. Once you've understood how that works, and understanding what datatypes make use of what (Vec! makes use of the heap for instance): You should be pretty proficient in Rust!
Upvotes: -3