Nick Cameron: Rust for C++ programmers - part 5: borrowed references |
fn foo() {The `&` operator does not allocate memory (we can only create a borrowed reference to an existing value) and if a borrowed reference goes out of scope, no memory gets deleted.
let x = &3; // type: &int
let y = *x; // 3, type: int
bar(x, *x);
bar(&y, y);
}
fn bar(z: &int, i: int) {
// ...
}
fn foo() {Like values, borrowed references are immutable by default. You can also use `&mut` to take a mutable reference, or to denote mutable reference types. Mutable borrowed references are unique (you can only take a single mutable reference to a value, and you can only have a mutable reference if there are no immutable references). You can use mutable reference where an immutable one is wanted, but not vice versa. Putting all that together in an example:
let x = 5; // type: int
let y = &x; // type: &int
let z = y; // type: &int
let w = y; // type: &int
println!("These should all 5: {} {} {}", *w, *y, *z);
}
fn bar(x: &int) { ... }Note that the reference may be mutable (or not) independently of the mutableness of the variable holding the reference. This is similar to C++ where pointers can be const (or not) independently of the data they point to. This is in contrast to unique pointers, where the mutableness of the pointer is linked to the mutableness of the data. For example,
fn bar_mut(x: &mut int) { ... } // &mut int is a reference to an int which
// can be mutated
fn foo() {
let x = 5;
//let xr = &mut x; // Error - can't make a mutable reference to an
// immutable variable
let xr = &x; // Ok (creates an immutable ref)
bar(xr);
//bar_mut(xr); // Error - expects a mutable ref
let mut x = 5;
let xr = &x; // Ok (creates an immutable ref)
//*xr = 4; // Error - mutating immutable ref
//let xr = &mut x; // Error - there is already an immutable ref, so we
// can't make a mutable one
let mut x = 5;
let xr = &mut x; // Ok (creates a mutable ref)
*xr = 4; // Ok
//let xr = &x; // Error - there is already a mutable ref, so we
// can't make an immutable one
//let xr = &mut x; // Error - can only have one immutable ref at a time
bar(xr); // Ok
bar_mut(xr); // Ok
}
fn foo() {If a mutable value is borrowed, it becomes immutable for the duration of the borrow. Once the borrowed pointer goes out of scope, the value can be mutated again. This is in contrast to unique pointers, which once moved can never be used again. For example,
let mut x = 5;
let mut y = 6;
let xr = &mut x;
//xr = &mut y; // Error xr is immutable
let mut x = 5;
let mut y = 6;
let mut xr = &mut x;
xr = &mut y; // Ok
let mut x = 5;
let mut y = 6;
let mut xr = &x;
xr = &y; // Ok - xr is mut, even though the referenced data is not
}
fn foo() {The same thing happens if we take a mutable reference to a value - the value still cannot be modified. In general in Rust, data can only ever be modified via one variable or pointer. Furthermore, since we have a mutable reference, we can't take an immutable reference. That limits how we can use the underlying value:
let mut x = 5; // type: int
{
let y = &x; // type: &int
//x = 4; // Error - x has been borrowed
println!("{}", x); // Ok - x can be read
}
x = 4; // OK - y no longer exists
}
fn foo() {Unlike C++, Rust won't automatically reference a value for you. So if a function takes a parameter by reference, the caller must reference the actual parameter. However, pointer types will automatically be converted to a reference:
let mut x = 5; // type: int
{
let y = &mut x; // type: &mut int
//x = 4; // Error - x has been borrowed
//println!("{}", x); // Error - requires borrowing x
let z = *y + x; // Ok - doesn't require borrowing
}
x = 4; // OK - y no longer exists
}
fn foo(x: &int) { ... }
fn bar(x: int, y: ~int) {
foo(&x);
// foo(x); // Error - expected &int, found int
foo(y); // Ok
foo(&*y); // Also ok, and more explicit, but not good style
}
fn foo() {In the above example, x and xr don't have the same lifetime because xr starts later than x, but it's the end of lifetimes which is more interesting, since you can't reference a variable before it exists in any case - something else which Rust enforces and which makes it safer than C++.
let x = 5;
let mut xr = &x; // Ok - x and xr have the same lifetime
{
let y = 6;
//xr = &y // Error - xr will outlive y
} // y is released here
} // x and xr are released here
http://featherweightmusings.blogspot.com/2014/05/rust-for-c-programmers-part-5-borrowed.html
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |