Why can't I assign one dereference of a reference of a reference to another when the outer lifetimes differ?

后端 未结 1 657
别跟我提以往
别跟我提以往 2020-12-21 01:32

I want to write the following function:

fn foo<\'a, \'b, \'c>(rr1: &\'a mut &\'c mut u32, rr2: &\'b mut &\'c mut u32) {
    *rr1 = *rr2         


        
相关标签:
1条回答
  • 2020-12-21 02:14

    You cannot dereference a &'b mut &'c mut u32 and get a &'c mut u32 because:

    • &mut references are not trivially copiable, so you can't copy the &'c mut u32; and
    • You cannot move out of a reference, so you also can't move the &'c mut u32 (which would leave the outer reference dangling).

    Instead, the compiler reborrows the u32 with the outer lifetime, 'b. This is why you get an error message that data from rr2 flows into rr1.

    If foo were allowed to compile, you could use it to get two &mut references to the same u32, which is forbidden by the rules of references:

    let (mut x, mut y) = (10, 20);
    let mut rx = &mut x;
    let mut ry = &mut y;
    foo(&mut rx, &mut ry); // rx and ry now both refer to y
    std::mem::swap(rx, ry); // undefined behavior!
    

    If I require that 'b outlives 'c, it works

    Because 'c must already outlive 'b¹, if you require that 'b also outlives 'c, it follows that 'c = 'b. The updated signature is equivalent to this:

    fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
    

    That is, you have unified 'c and 'b, and now there's no problem borrowing a &'b mut u32 from rr2 because the inner and outer lifetimes both live for 'b. However, the compiler now won't let you write the broken code in the example I gave earlier, since ry is already borrowed for its entire lifetime.

    Interestingly, if you make the inner reference non-mut, it also works:

    fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
        *rr1 = *rr2;
    }
    

    This is because & references are Copy, so *rr2 is not a reborrow, but actually just a copy of the inner value.

    For more information, read:

    • Why does linking lifetimes matter only with mutable references?
    • How can I modify a slice that is a function parameter?

    ¹ It might not be obvious why 'c outlives 'b when there is no explicit 'c: 'b bound. The reason is because the compiler assumes that the type &'b mut &'c mut u32 is well-formed. Well-formedness can become complex (see RFC 1214) but in this case it just means you can't have a reference that's valid for longer ('b) than the thing it references ('c).

    0 讨论(0)
提交回复
热议问题