我在Rust书中看到,您可以定义两个具有相同名称的不同变量:
let hello = "Hello";
let hello = "Goodbye";
println!("My variable hello contains: {}", hello);
打印出来:
My variable hello contains: Goodbye
第一次问候怎么了?它被释放了吗?我怎么能访问它?
我知道将两个变量命名为相同是不好的,但是如果这种情况偶然发生,因为我将其声明为100行,这可能是一个真正的痛苦。
答案 0 :(得分:12)
Rust does not have a garbage collector
Rust是否释放了被覆盖变量的内存?
是的,否则会造成内存泄漏,这将是一个非常糟糕的设计决定。
第一个问候
会发生什么
是shadowed。
没什么"特别"发生在变量引用的数据上,而不是您无法再访问它。当变量超出范围时,它仍然被丢弃。
这里的代码在每个变量被删除时打印出来:
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) {
println!("Dropped")
}
}
fn main() {
println!("0");
let thing = Noisy;
println!("1");
let thing = Noisy;
println!("2");
}
0
1
2
Dropped
Dropped
我知道将两个变量命名为相同
是不好的
它不是"糟糕"它是一个设计决定。我会说像这样使用阴影是一个坏主意:
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 {}", x);
另见:
但是如果这种情况偶然发生,因为我宣布它下面100行,那可能是一个真正的痛苦。
不要有太大的功能,以至于你不小心"做一点事。这适用于任何编程语言。
有没有办法手动清理记忆?
您可以致电drop
:
println!("0");
let thing = Noisy;
drop(thing);
println!("1");
let thing = Noisy;
println!("2");
0
Dropped
1
2
Dropped
但是,作为oli_obk - ker points out,变量占用的堆栈内存在函数退出之前不会被释放,只有变量占用的资源才会释放。
所有关于drop的讨论都需要显示其(非常复杂的)实现:
fn drop<T>(_: T) {}
如果我在其他函数之外的全局范围内声明变量怎么办?
如果您甚至可以创建全局变量,那么它们永远不会被释放。
答案 1 :(得分:7)
在删除订单时, shadowing 和覆盖变量之间存在差异。
所有局部变量通常在超出范围时被删除,与声明的顺序相反(参见 Rust编程语言&#39; s chapter on Drop
)。这包括阴影变量。很容易通过将值包装在一个简单的包装器结构中来检查这一点,该结构在它(包装器)被删除时打印一些东西(只是在之前删除值本身):
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);
}
打印以下内容(playground):
My variable hello contains: Goodbye
dropping "Goodbye"
dropping "Hello"
那是因为范围中新的let
绑定不会覆盖以前的绑定,所以它就像你写的那样
let hello1 = NoisyDrop("Hello");
let hello2 = NoisyDrop("Goodbye");
println!("My variable hello contains: {}", hello2.0);
请注意,此行为与以下表面上非常相似的代码(playground)不同:
fn main() {
let mut hello = NoisyDrop("Hello");
hello = NoisyDrop("Goodbye");
println!("My variable hello contains: {}", hello.0);
}
不仅会以相反的顺序丢弃它们,而是在打印消息之前删除第一个值!这是因为当您分配给变量(而不是使用新变量进行遮蔽)时,在移入新值之前,原始值将首先首先删除。
我首先说局部变量是&#34;通常&#34;当他们超出范围时掉线。因为您可以将值移入和移出变量,所以在运行时有时无法进行分析以确定何时需要被丢弃。在这种情况下,编译器实际上是inserts code to track "liveness" and drop those values when necessary,因此您不能通过覆盖值而意外地导致泄漏。 (但是,通过调用mem::forget
或通过创建具有内部可变性的Rc
循环,仍然可以安全地泄漏内存。)