一、RAII
RAII源自于现代C++,Rust 强制实行 RAII(Resource Acquisition Is Initiallization,资源获取即初始化),所以任何对象在离开作用域时,它的析构函数(destructor)就被调用,然后它占有的资源就被释放。
这种行为避免了资源泄漏(resource leak),所以你再也不用手动释放内存或者担心内存泄漏(memory leak)!
小示例:
fn main() {
//嵌套作用域:
{
let _box3 = Box::new(4i32); //在堆上分配一个整型数据
} //`_box3`在这里被销毁,内存得到释放
}
二、析构函数
Rust 中的析构函数概念是通过 Drop
trait 提供的。当资源离开作用域,就调用析构函数。
你无需为每种类型都实现 Drop
trait,只要为那些需要自己的析构函数逻辑的类型实现就可以了。
#[derive(Debug)]
struct ToDrop{x:i32,y:i32}
impl Drop for ToDrop{
fn drop(&mut self){
println!("droping!");
}
}
fn main() {
let to_drop = ToDrop{x:12,y:23};
println!("Hello, world!=={:?}",to_drop);
}
// Hello, world!==ToDrop { x: 12, y: 23 }
// droping!
三、所有权和移动
这里主要是涉及在堆中申请的内容,为了极致的性能,指向堆中对象的指针,在进行多次绑定时会涉及到所有权和移动。但是我们也可以对指向堆中对象进行复制,不过这需要实现clone trait。
fn destroy_box(c:Box<u8>){
println!("Droping box !!! {}",c);
}
fn main() {
let x = 12u8;
let y = x;
println!("x is {}, and y is {}", x, y); // rust 对基础数据类型实现了copy,故不存在资源移动
let a = Box::new(255u8);
println!("a contains {},",a);
let b = a;
println!("b contains {}",b);
destroy_box(b);
// println!("a contains {}", a) // 报错!`a`不能访问数据
// println!("b contains: {}", b); // 报错!`b`不能访问数据
}
四、可变性
当所有权转移时,数据的可变性可能发生改变。
fn drop_box(box_i32:Box<i32>){
println!("Droping box contain {}!!!",box_i32);
}
fn borrow_box(borrow_i32:&i32){
println!("Only print value is {}",borrow_i32)
}
fn main() {
let box1 = Box::new(100u8);
let mut box2 = Box::new(200u8);
*box2 = 255u8;
println!("box1 contains is {}",box1);
println!("box2 contains is {}",box2);
let box_i32 = Box::new(100i32);
let stack_i32 = 100i32;
borrow_box(&box_i32);
borrow_box(&stack_i32);
drop_box(box_i32);
}
// box1 contains is 100
// box2 contains is 255
// Only print value is 100
// Only print value is 100
// Droping box contain 100!!!
五、可变引用
可变数据可以使用 &mut T
进行可变借用。这叫做可变引用(mutable reference),它使
借用者可以读/写数据。相反,&T
通过不可变引用(immutable reference)来借用数据,
借用者可以读数据而不能更改数据。
#[derive(Clone, Copy)]
struct Book{
author: &'static str,
title: &'static str,
year: u32,
}
fn borrow_book(book:&Book){
println!("I immutable borrowed author =>{} title =>{} year =>{}",
book.author, book.title,book.year);
}
fn new_edition(book:&mut Book){
book.year = 2000;
println!("I mutable borrowed author =>{} title =>{} year =>{}",
book.author, book.title,book.year);
}
fn main(){
let immut_book = Book{
author:"Douglas Hofstadter", //字符串字面量拥有`&'static str`类型
title:"Escher, Bach",
year: 2001,
};
let mut mut_book = immut_book; //创建一个`immutabook`的可变拷贝 #[derive(Clone, Copy)]
borrow_book(&immut_book); //不可变地借用一个不可变对象
borrow_book(&mut_book); //不可变地借用一个可变对象
new_edition(&mut mut_book); //可变地借用一个可变对象
}
如上,禁止可变地借用一个不可变对象,若这样写会编译报错。