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
1.7k views
in Technique[技术] by (71.8m points)

rust - Why do I need rebinding/shadowing when I can have mutable variable binding?

Why do I need rebinding/shadowing when I can have mutable variable binding? Consider:

let x = a();
let x = b(x);

vs.

let mut x = a();
x = b(x);

Mutable variable binding allows a mutable borrow of that variable over this. But does shadowing have some advantages over mutable bindings?

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

Because the two have totally different effects.


To really understand what is going on, we need to start at the beginning: what is a binding? What does binding mean?

Let's consider a simple function: fn hello() -> String;.

When invoking this function like so:

fn main() {
    hello();
}

What happens?

The function returns a String, which is promptly discarded (executing Drop as it is thereby freeing its memory).

The result is dropped because it was not bound to a variable name, and the rules of the language say that if not bound then it can be promptly dropped1.

If we bind this result, however, we prolong the life of this value, and we can access it via this binding... for a while.

fn main() {
    let value = hello();

    std::mem::drop(value);

    println!("{}", value); // Error: moved out of value
}

This is the issue at hand: in Rust, the lifetime of a value is independent from the scope of a binding.

A value need not even be dropped before its binding exits its scope: it can be transferred to another (similar to returning from a function).

fn main() {
    let x;
    {
        let y = hello();
        x = y;
    }
    println!("{}", x);
}

1 the same happens if binding to _.


So, now we armed with the fact that bindings and values differ, let's examine the two snippets.

A first shadowing snippet, differing from yours:

fn main() {
    let x = a();
    let x = b();
}

Steps, in order:

  • The expression a() creates a value, which is bound to x
  • The expression b() creates a value, which is bound to x
  • The value created by b() is dropped
  • The value created by a() is dropped

Note that the fact that x is re-bound does not affect the lifetime of the value that was previously bound.

Technically, it behaves exactly as if the result of b() was bound to y, with the sole exception that the previous x binding is not accessible while y is in scope.

Now, the mutable snippet:

fn main() {
    let mut x = a();
    x = b();
}

Steps, in order:

  • The expression a() creates a value, which is bound to x
  • The expression b() creates a value, which is bound to x, and the previous value (created by a()) is dropped
  • The value created by b() is dropped

Once again, accessing the previous value is impossible, however whilst with shadowing it's impossible temporarily (if shadowing in a smaller scope), with assignment it's impossible forever since the value is dropped.


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

...