Skip to content

Instantly share code, notes, and snippets.

@jviereck
Created March 26, 2015 21:14
Show Gist options
  • Select an option

  • Save jviereck/227377d9b27157ad4359 to your computer and use it in GitHub Desktop.

Select an option

Save jviereck/227377d9b27157ad4359 to your computer and use it in GitHub Desktop.
// Goal of this file:
// Figure out in which cases a "move" or a "borrow" operation is performed
// by the rust compiler.
//
// Finding:
// - A "simple" assignment without defining the type on the local variable
// cause the field to be moved:
//
// let id_ref = entry.id; // entry.id is moved!
//
// - Defining the type on the local variable causes a borrow of the field's
// borrowed value. Note that no `&mut` is required in this case for the RHS!
//
// let id_ref: &mut isize = entry.id;
//
// - Using an `&mut` operation does not take a new borrow from the borrowed
// value itself but creates a new borrow to the field itself (you end up
// with a double pointer when following the terminology of C/C++). The
// type in the following case if then of `&mut &mut isize`.
//
// let id_ref = &mut entry.id;
//
// - The two following notations are equivalent:
//
// let id_ref = &mut entry.id;
// let ref mut id_ref = entry.id;
//
struct Entry<'a> {
id: &'a mut isize
}
fn owned_field_move() {
let mut id = 1;
let entry = Entry { id: &mut id };
// The following statement will MOVE the content of the entry.id field. That
// means, that the `id_ref` contains the `&mut isize`. The type of `id_ref`
// is `&mut isize`.
let id_ref = entry.id;
// ATTEMPT FAILS
// The following line is rejected by the rust compiler as the line above moved
// value `entry.id` out already.
//
// error: use of moved value: `entry.id`
//
// println!("entry.id={}", entry.id);
}
fn owned_field_typedef() {
let mut id = 1;
let entry = Entry { id: &mut id };
// The following statement will BORROW the content of the `entry.id` by taking
// an mutable borrow on it.
// -> When a type signature is specified on the local variable, then a borrow
// is performed over a move.
let id_ref: &mut isize = entry.id;
*id_ref = 1;
println!("entry.id={}", id_ref);
// ATTEMPT FAILS
// As above, the following lines is rejected. HOWEVER, the reason is different
// here - the statement is rejected, as the `entry.id` is now mutable borrowed
// to `id_ref`.
//
// error: cannot borrow `entry.id` as immutable because `*entry.id` is also
// borrowed as mutable
//
// println!("entry.id={}", entry.id);
}
fn owned_field_mut_borrow() {
let mut id = 1;
let entry = Entry { id: &mut id };
// ATTEMPT FAILS
// The following statement will not work. Note that the return type of the RHS
// with the `&mut` operation is of type `&mut &mut isize`. So, instead of
// "just taking a new borrow" on the existing field type, the operation tries
// to create a double pointer/borrow to the `entry.id` field. But that is not
// allowed, as `entry` is immutable, therefore all its fields are also immutable
// and therefore the `id` field is immutable and the compiler therefore rejects
// the mutable borrow attempt.
//
// cannot borrow immutable field `entry.id` as mutable
//
// let id_ref = &mut entry.id;
// NOTE: The line
//
// let ref mut id_ref = entry.id;
//
// is equivalent to specifing the `&mut` on the RHS as in
//
// let id_ref = &mut entry.id;
}
fn main() {
owned_field_move();
owned_field_typedef();
owned_field_mut_borrow();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment