8

I'm trying Rust and have issues with understanding "borrowing".

struct Foo<T> {
    data: T,
}

impl<T> Foo<T> {
    fn new(data: T) -> Self {
        Foo {
            data: data,
        }
    }
}

fn main() {
    let mut foo = Foo::new("hello");

    let x = &mut foo;
    let y = &mut foo;

    println!("{}", foo.data);

}

Why this code compile without error? After all, I'm get a multiple mutable references on foo. The following is written to documentation:

The Rules of References
Let’s recap what we’ve discussed about references:

a) At any given time, you can have either (but not both of) one mutable reference or any number of immutable references.

b) References must always be valid.

What is the reason for this behavior? Thanks!

Sargis
  • 101
  • 1
  • 2

2 Answers2

11

You are probably benefiting from non-lexical lifetimes which have been enabled by default since Rust 1.30 while using the 2018 edition.

See also What are non-lexical lifetimes?.

mcarton
  • 27,633
  • 5
  • 85
  • 95
4

On my rust version (1.29.1), I do have the multi-borrow errors.

I think you are benefiting from non-lexical lifetimes here, that or the compiler smartly optimizes* the code as:

let mut foo = Foo::new("hello");

{ let x = &mut foo; }
{ let y = &mut foo; }

println!("{}", foo.data);

which works because you are not using x and y.

*: from @mcarton: optimizations occurs after the borrow-check pass, so the only option is NLL.

  • I use nightly version Rust. Maybe because of this. – Sargis Oct 20 '18 at 20:19
  • Thanks for the answer. When i add println!("{}", x.data); and println!("{}", y.data); it does not compile. And sorry for my bad english... – Sargis Oct 20 '18 at 20:25
  • 1
    NLL are not an optimization. The borrow-checker does its job before any optimization and is a purely semantic and artificial restriction, so the "smartly optimizes the code as" remark makes no sense. – mcarton Oct 20 '18 at 21:53