Skip to content

Instantly share code, notes, and snippets.

@stevenblenkinsop
Forked from anonymous/playground.rs
Last active October 13, 2015 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenblenkinsop/aea9aef9db602410b683 to your computer and use it in GitHub Desktop.
Save stevenblenkinsop/aea9aef9db602410b683 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
fn main() {
#![allow(unused)]
// A borrow can be moved out of the scope where it is created as long as the original value is
// known to live long enough. Here it is assigned to `out`. While `out` is in scope, `x` is
// inaccessible. When `out` goes out of scope, `x` becomes accessible again:
{
fn bar<'a>(x: &'a mut u32) -> &'a mut u32 { x }
let mut x = 1;
{
let out = { bar(&mut x) };
// println!("{}", x);
// > error: cannot borrow `x` as immutable because it is also borrowed as mutable
}
println!("{}", x);
}
// If `out` lives in the same scope as `x`, then the borrow has to live as long as `x`, and
// so `x` never becomes accessible again:
{
fn bar<'a>(x: &'a mut u32) -> &'a mut u32 { x }
let mut x = 1;
let out = { bar(&mut x) };
// println!("{}", x);
// > error: cannot borrow `x` as immutable because it is also borrowed as mutable
}
// A borrow can also escape through an `&mut` parameter with the right lifetime:
{
fn bar<'a>(x: &'a mut u32, out: &mut &'a mut u32) { *out = x }
let mut x = 1;
let mut out = &mut 2;
{ bar(&mut x, &mut out); };
// println!("{}", x);
// > error: cannot borrow `x` as immutable because it is also borrowed as mutable
}
// This works even if the borrowed value and the `&mut` it escapes into are part of the same
// parameter:
{
fn bar<'a>(x: &'a mut(u32, &'a mut u32)) { x.1 = &mut x.0 }
let mut x = (1, &mut 2);
{ bar(&mut x); }
// println!("{}", x.0);
// > error: cannot borrow `x.0` as immutable because `x` is also borrowed as mutable
}
// If you factor that into a struct, you get something like the original example:
{
struct Foo<'a>{a: u32, b: &'a mut u32}
fn bar<'a>(x: &'a mut Foo<'a>) { x.b = &mut x.a }
let mut x = Foo{a: 1, b: &mut 2};
{ bar(&mut x); }
// println!("{}", x.a);
// > error: cannot borrow `x.a` as immutable because `x` is also borrowed as mutable
}
// Note that in each case, I've actually made the borrow escape in order to show that it
// can. However, the actual implementation of `bar` is not important. The borrow checker
// bases its analysis of `main` only on the signature of the function `bar`. Also, I've
// conveniently set up the types in order to make it easy for the borrow to escape. This
// also isn't necessary. I can do the same thing even if it's not practical to do so.
// This makes the analysis more consistent and predictable, and makes it easier to
// leverage the borrow checker to provide safe abstractions over unsafe code.
{
fn bar<'a>(x: &'a mut &'a u32) {}
let mut x = &2;
{ bar(&mut x); }
// println!("{}", x);
// > error: cannot borrow `x` as immutable because it is also borrowed as mutable
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment