Skip to content

Instantly share code, notes, and snippets.

@jimblandy
Created January 4, 2017 23:00
Show Gist options
  • Save jimblandy/b4fe875939bf5e2a789d03348ef9c50e to your computer and use it in GitHub Desktop.
Save jimblandy/b4fe875939bf5e2a789d03348ef9c50e to your computer and use it in GitHub Desktop.
Generic functions and implicit reborrows

Consider the following code:

#![allow(dead_code)]

fn f    (x: &mut i32) -> &mut i32 { x }
fn id<T>(x: T       ) -> T        { x }

fn main() {
    let mut x = 10;
    let m = &mut x;
    f(m);
    *m = 11;
}

Note that f and id are identical, except that id replaces &mut i32 with a type parameter.

As written, this code compiles. Although m is a &mut i32, which is not Copy, the call to f does not move the reference out of m, because Rust implicitly rewrites such calls to f(&mut *m). This allows the argument a lifetime distinct from m's, one which ends immediately after the call.

However, if you change f(m) to id(m), the program no longer compiles: Rust complains that the assignment to *m is trying to use m after it was moved, and points out that &mut i32 is not Copy.

Finally, if you change id(m) to id::<&mut i32>, the program does compile. This was a surprise to me. My guess is that inferring id's type parameter unifies the T with m's type, so that T has the same lifetime as m, and that Rust only introduces reborrows when the parameter and argument have non-related lifetimes (the reborrow won't have any effect unless they do, anyway).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment