繁体   English   中英

Rust中相同作用域中的可变阴影?

[英]Variable shadowing in the same scope in Rust?

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

    let x = 3.14;
    println!("{}", x);

    let x = "Hello";
    println!("{}", x);
}
  1. 以前的值会怎样? 我的理解是它们没有被摧毁。

  2. 有没有办法访问这些值?

  3. 如果它们仍在消耗内存空间,是否可以释放该空间?

  1. 以前的值会怎样?

没有。

  1. 有没有办法访问这些值?

没有。

  1. 如果它们仍在消耗内存空间,是否可以释放该空间?

没有。


现在,从代码的角度来看,以上所有内容都应该是正确的。 优化器的角度来看,它们不一定是正确的。 例如,优化器可能会注意到第一个x和第二个x的用法不重叠,因此它可以将第一个x的堆栈存储重用于第二个x

否则可能不会。 就我所知,语言本身对此主题没有意见。

我知道,可以保证局部变量一定释放其堆栈存储的唯一方法是从其定义的函数中返回。

...好吧,直到您考虑内联 ,这也可能使之不成立。

简短版:不用担心,除非您使用了太多的堆栈空间,否则会引起实际的,可测量的问题。

该值可以在变量被屏蔽之前移出,但最终无法从阴影变量访问该值。

问题1的答案: 决定取决于编译器 ,数据类型和大小以及操作系统和系统内存负载(通常,基于堆栈的数据类型停留在main的末尾,如果占用空间大,基于堆的数据类型可能需要删除)需要)。
问题2的答案:阴影之后: ,阴影之前:是( ),运行此代码
问题3的答案:阴影之后: ,阴影之前:请参阅: 处置一个值 Rust手动内存管理


可变范围和阴影:
好处:
1.由于无法从外部范围访问数据,因此保留了数据完整性。
2.当“我们需要更多字母”时,这是限制变量范围的好方法。 当您需要更多局部变量或范围时,此方法也很好用。


在遮蔽之前仍可访问这些值的一种方法(注意:move强制闭包获得'x'的所有权):

use std::{thread, time};
fn main() {
    let mut v = vec![];
    let d = time::Duration::from_millis(100);

    let x = 5;
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 1: {}", x);
        }
    }));

    let x = 3.14;
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 2: {}", x);
        }
    }));

    let x = "Hello";
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 3: {}", x);
        }
    }));

    for child in v {
        let _ = child.join();
    }
}

输出:

5
3.14
Hello
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello

注意: move强制闭包获得'x'的所有权,因此本地x的地址与线程x是:

use std::thread;
fn main() {
    let mut v = vec![];

    let x = 5;
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 1: {:p}", &x);
    }));

    let x = 3.14;
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 2: {:p}", &x);
    }));

    let x = "Hello";
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 3: {:p}", &x);
    }));

    for child in v {
        let _ = child.join();
    }
}

输出:

0x8bf934
0x8bf9b8
0x8bfa40
Thread 1: 0x4a3faec
Thread 2: 0x4c3fae8
Thread 3: 0x4e3fa70

据我所知,关于阴影,只有一件事要牢记:当值被堆分配时。

书中

请注意,为名称加上阴影不会改变或破坏它所绑定的值,并且该值将继续存在,直到超出范围为止,即使它无法以任何方式访问

上一个值在阴影化之后不再可访问,并且它将在作用域末尾而不是在变量被阴影化时销毁。

如果值在堆栈上,则无需担心:堆栈内存管理完全在处理器手中。

相反,如果该值是堆分配的,则影子可以看作是临时内存泄漏,它将在作用域末尾释放。

如果这可能是一个问题,我们可以在阴影之前使用drop()显式释放内存:

struct Foo {
    _v: Vec<i32>
}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("dropping foo");
    }
}


fn main() {
    println!("start");

    let x = Foo {_v: vec![1,2,3]};

    drop(x);

    let x = 100;

    println!("end");

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM