Rust中相同范围内的变量阴影?

时间:2018-04-22 03:30:49

标签: variables types rust

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

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

    let x = "Hello";
    println!("{}", x);
}
  1. 以前的值会发生什么变化?我的理解是他们没有被摧毁。

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

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

3 个答案:

答案 0 :(得分:4)

  
      
  1. 以前的值会发生什么变化?
  2.   

没有

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

没有

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

没有

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

或者它可能没有。就我所知,语言本身对此问题没有任何意见。

我知道你可以保证局部变量肯定释放它的堆栈存储的唯一方法是从它定义的函数返回。< / p>

......好吧,直到你考虑内联,这也可能使其不正确。

简短版本:不要担心,除非你使用这么多的堆栈空间导致实际的,可测量的问题。

答案 1 :(得分:1)

  

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

对Q1的回答:决定取决于编译器,数据类型和大小以及操作系统和系统内存负载(通常基于堆栈的数据类型保持在main的末尾,如果需要,可能需要丢弃具有大内存占用量的基于堆的数据类型 回答Q2:阴影后:,在投影前:是(),运行this code
回答第3季:遮蔽之后:,在遮蔽之前:参见:Disposes of a value。和Rust manual memory management

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

在遮蔽之前仍然可以访问这些的方法(注意:移动强制关闭以取得'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

答案 2 :(得分:0)

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

来自book

  

请注意,遮蔽名称不会改变或破坏它所绑定的值,并且该值将继续存在,直到它超出范围,即使它无法通过任何方式访问

在阴影之后,以前的值不可访问,它将是 在范围的末尾被破坏,而不是在变量被遮蔽时被破坏。

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

相反,如果值是堆分配的,则可以将阴影视为临时内存泄漏,将在范围的末尾发布。

如果这可能是一个问题,我们可以在遮蔽之前用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");

}
相关问题