Memory management 生锈会释放被覆盖变量的内存吗?

Memory management 生锈会释放被覆盖变量的内存吗?,memory-management,rust,Memory Management,Rust,我在Rust书中看到,可以用相同的名称定义两个不同的变量: let hello = "Hello"; let hello = "Goodbye"; println!("My variable hello contains: {}", hello); 这将打印出: 我的变量hello包含:再见 第一次打招呼会发生什么?它被释放了吗?我怎样才能访问它 我知道给两个变量取相同的名字是不好的,但如果这是偶然发生的,因为我在下面100行处声明了它,这可能是一个真正的痛苦。 生锈会释放被覆盖变量的内存

我在Rust书中看到,可以用相同的名称定义两个不同的变量:

let hello = "Hello";
let hello = "Goodbye";

println!("My variable hello contains: {}", hello);
这将打印出:

我的变量hello包含:再见
第一次打招呼会发生什么?它被释放了吗?我怎样才能访问它

我知道给两个变量取相同的名字是不好的,但如果这是偶然发生的,因为我在下面100行处声明了它,这可能是一个真正的痛苦。

生锈会释放被覆盖变量的内存吗

是的,否则将是内存泄漏,这将是一个非常糟糕的设计决策。重新分配变量时将释放内存:

struct Noisy;
impl Drop for Noisy {
    fn drop(&mut self) {
        eprintln!("Dropped")
    }
}

fn main() {
    eprintln!("0");
    let mut thing = Noisy;
    eprintln!("1");
    thing = Noisy;
    eprintln!("2");
}
0
1.
下降
2.
下降
第一次打招呼会发生什么

是的

变量引用的数据没有任何“特殊”情况,只是您无法再访问它。当变量超出范围时,它仍然会被删除:

struct Noisy;
impl Drop for Noisy {
    fn drop(&mut self) {
        eprintln!("Dropped")
    }
}

fn main() {
    eprintln!("0");
    let thing = Noisy;
    eprintln!("1");
    let thing = Noisy;
    eprintln!("2");
}
0
1.
2.
下降
下降
另见:

我知道给两个变量取相同的名字是不好的

这不是“坏”,这是一个设计决定。我想说,像这样使用阴影是个坏主意:

let x = "Anna";
println!("User's name is {}", x);
let x = 42;
println!("The tax rate is {}", x);
这样使用阴影对我来说是合理的:

let name = String::from("  Vivian ");
let name = name.trim();
println!("User's name is {}", name);
另见:

但如果这是偶然发生的,因为我宣布它在100行以下,这可能是一个真正的痛苦

不要有太大的函数以至于你“意外”做了一些事情。这适用于任何编程语言

有没有办法手动清理内存

你可以致电:

0
下降
1.
2.
下降
但是,由于变量占用的堆栈内存在函数退出之前不会被释放,只有变量占用的资源才会被释放

所有关于
drop
的讨论都需要显示其(非常复杂)的实现:

fn drop<T>(_: T) {}
fn-drop(u:T){
如果我在其他函数之外的全局范围内声明变量会怎么样


全局变量永远不会被释放,如果你甚至可以创建它们作为开始。

当涉及到删除顺序时,隐藏和重新分配(覆盖)变量是有区别的

所有局部变量通常在超出范围时被删除,顺序与声明相反(请参阅Rust编程语言的)。这包括阴影变量。通过将值包装在一个简单的包装器结构中,可以很容易地检查这一点,该结构在删除该值(包装器)时(就在删除该值之前)打印一些内容:

这是因为作用域中新的
let
绑定不会覆盖以前的绑定,因此就像您编写了

    let hello1 = NoisyDrop("Hello");
    let hello2 = NoisyDrop("Goodbye");

    println!("My variable hello contains: {}", hello2.0);

请注意,此行为与下面的代码()不同,表面上非常相似:

这不仅会以相反的顺序删除它们,还会在打印消息之前删除第一个值!这是因为当你赋值给一个变量(而不是用一个新的变量来隐藏它)时,在新值移入之前,原始值会先被删除

我首先说,局部变量在超出范围时“通常”会被删除。因为您可以将值移入和移出变量,所以有时要等到运行时才能完成确定何时需要删除变量的分析。在这种情况下,编译器实际上会自动关闭,因此您不会因为覆盖某个值而意外导致泄漏。(但是,通过调用
mem::forget
,或者通过创建具有内部可变性的
Rc
-循环,仍然可以安全地泄漏内存。)

另见

1。Rust甚至没有GC。2.这应该在《我知道锈菌没有GC》一书中解释,但事实上,锈菌在没有你告诉它某种程度上是GC的情况下会自行清洗。有没有办法手动清理内存?还是像谢普马斯特提到的那样,内存只有在超出范围后才会被释放?这不是你在问题中要问的。我不明白为什么这个问题会被否决。铁锈书根本没有解释隐藏变量的记忆会发生什么。来自@Shepmaster的答案很好地解释了这一点@LoganReed如果你检查,你会看到OP最初询问Rust的“垃圾收集器”是X还是Y。向下投票箭头工具提示将“这个问题没有显示任何研究成果”列为使用它的理由。粗略的搜索会显示Rust没有GC,所以我猜人们是因为这些原因的组合而被否决的。如果你认为这个问题的当前形式是好的,你会被鼓励去投票。我知道Rust没有GC,但是事实上它会在没有你告诉它某种程度上是GC的情况下自行清理。有没有办法手动清理内存?如果我在其他函数之外的全局范围内声明变量会怎么样?好的,当它超出范围时,它会再次释放内存。你知道是否有手动的方法,还是Rust自己决定的?你在释放内存方面有一个基本问题:堆栈(根据定义)只能在顶部(或底部,取决于你的视图)进行修改。所以你不能在中间释放“内存”。如果按此顺序有3个变量
a
b
c
,则不能“释放”
b
,您可以停止使用它或重用它的内存,但不能释放它。
use std::fmt::Debug;

struct NoisyDrop<T: Debug>(T);

impl<T: Debug> Drop for NoisyDrop<T> {
    fn drop(&mut self) {
        println!("dropping {:?}", self.0);
    }
}

fn main() {
    let hello = NoisyDrop("Hello");
    let hello = NoisyDrop("Goodbye");

    println!("My variable hello contains: {}", hello.0);
}
    let hello1 = NoisyDrop("Hello");
    let hello2 = NoisyDrop("Goodbye");

    println!("My variable hello contains: {}", hello2.0);
fn main() {
    let mut hello = NoisyDrop("Hello");
    hello = NoisyDrop("Goodbye");

    println!("My variable hello contains: {}", hello.0);
}