Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
651 views
in Technique[技术] by (71.8m points)

reference - Mutable borrow in a loop

I have the following code:

struct Baz {
    x: usize,
    y: usize,
}

struct Bar {
    baz: Baz,
}

impl Bar {
    fn get_baz_mut(&mut self) -> &mut Baz {
        &mut self.baz
    }
}

struct Foo {
    bar: Bar,
}

impl Foo {
    fn foo(&mut self) -> Option<&mut Baz> {
        for i in 0..4 {
            let baz = self.bar.get_baz_mut();
            if baz.x == 0 {
                return Some(baz);
            }
        }
        None
    }
}

Rust Playground

It fails to compile with:

error[E0499]: cannot borrow `self.bar` as mutable more than once at a time
  --> src/main.rs:23:23
   |
23 |             let baz = self.bar.get_baz_mut();
   |                       ^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
29 |     }
   |     - mutable borrow ends here

However, if I return Some(baz.x) from Foo::foo (and change the return type to Option<usize>), the code compiles. This makes me believe the problem is not with the loop even though the compiler seems to indicate so. More specifically, I believe the local mutable reference baz would go out of scope at the next iteration of the loop, causing this to be a non-problem. What is the lifetime problem with the above code?

The following questions are similar:

However, they deal with explicitly declared lifetimes (and specifically these explicit lifetimes are part of the answer). My code omits these lifetimes so removing them is a non-solution.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It does not work because returning a borrowed value extends the borrow to the end of the function.

See here for some useful details.

This works with non-lexical lifetimes with the 1.27 nightly version:

#![feature(nll)]

struct Baz {
    x: usize,
    y: usize,
}

// ...

The non-lexical lifetimes RFC explains the actual working of lifetimes:

Problems arise however when you have a reference that spans multiple statements. In that case, the compiler requires the lifetime to be the innermost expression (which is often a block) that encloses both statements, and that is typically much bigger than is really necessary or desired

rustc nightly 1.28

As pointed out by @pnkfelix, the non-lexical lifetimes implementation starting from nightly 1.28 no longer compiles the above code.

There is however a long-term plan to (re)-enable a more powerful NLL analysis.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...