-
-
Save stevenblenkinsop/aea9aef9db602410b683 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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