在生锈的同一范围内的可变阴影


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

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

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

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

什么都没有。

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

no。

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

no。


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

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

我意识到的唯一方法是,您可以保证 local变量将绝对释放其堆栈存储是从定义的函数中返回的。<<<<<<<<<<<<<<<<<<<</p>

...好吧,直到您考虑 inling ,这也可能使它不正确。

简短版本:不用担心,除非您使用的是太多的堆栈空间,从而导致了实际的,可衡量的问题。

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

回答Q1:决策取决于编译器以及数据类型,大小以及OS和系统内存加载(通常基于堆栈的数据类型保持到main的末尾,以及基于HEAP的数据带有大型内存足迹的类型可能需要在需要时掉落(。
回答Q2:阴影后:,在阴影之前:是( values (,运行此代码。
回答Q3:阴影后:,在阴影之前:请参阅:处置值。和生锈手动记忆管理


可变范围和阴影:
优点:
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不同,但是 value is:

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");
}

最新更新