所有权
rust中所有权是对变量所指向内存的一种抽象。在内存的空间性加上时间性这个特性。内存的空间性是指它具有的唯一内存地址。但我们往往忽略了内存的时间性。体现了内存时间性最为明显的地方一个是局部变量所指向的内存,一个是堆上的内存。
局部变量所指向的内存随时被回收,堆上的内存永远不知道什么时候被回收。
rust通过所有权机制保证了,只要拥有所有权的变量在此时所指向的内存(资源)一定存在。
我们知道变量是什么时候获得内存,但什么时候释放它是一个问题?
rust通常通过作用域来决定什么时候释放资源。注意这里指的是资源,资源不只是内存。
作用域
作用域的声明为{}。
只要是{}所包裹的代码块都看作一个作用域。当一个作用域结束,rust会释放所有拥有所有权资源的变量。
let mut x = String::from("hello world");
{
let mut y = x;
y.push('!');
println!("{:?}", y);
}
println!("{:?}", x);
在上面的代码中,第三行y获得了x的所有权,然后在第六行释放了所有权。所以当第7行再次获取x的时候,会报错。
注意:x此时还存在,只是编译器检查的时候,发现所有权已经转移,禁止访问了。
{
let mut x = String::from("hello world");
x.push('!');
println!("{:?}", x);
}
println!("{:?}", x);
drop
我们知道了变量会在作用域结束的时候释放资源,但怎么释放,其实是掌握在编写者的手中,在其他语言中,这个函数通常叫做析构函数,在rust中,我们使用drop这个trait来完成。
注:trait,rust中用来组织函数的语法。
struct TestDrop;
impl Drop for TestDrop {
fn drop(&mut self) {
println!("TestDrop drop!");
}
}
println!("start!");
{
let _x = TestDrop {};
}
println!("end!");
运行上面代码,会出现下述情况。
start!
TestDrop drop!
end!
紧接着上面的代码,我们看下rust如何drop一个复杂数据类型(自定义数据类型)。代码如下:
struct TestDrop;
impl Drop for TestDrop {
fn drop(&mut self) {
println!("TestDrop drop!");
}
}
struct TestDropTwo {
one: TestDrop,
two: TestDrop,
}
impl Drop for TestDropTwo {
fn drop(&mut self) {
println!("TestDropTwo drop!");
}
}
println!("start!");
{
let _x = TestDropTwo {
one: TestDrop {},
two: TestDrop {},
};
}
println!("end!");
}
上述代码会输出如下结果:
start!
TestDropTwo drop!
TestDrop drop!
TestDrop drop!
end!
通过结果可知,拥有所有权的变量离开作用域后,会自动调用drop来回收资源。drop函数从最高级的抽象开始,逐步向下调用,直至资源回收干净。需要注意的是,实现了Copy这个trait的变量来离开作用域是不会触发drop。