RiverMao

从未来再见

Rust特性(1)--所有权,深浅拷贝,引用,借用,悬空引用(野指针)

2022-05-31


内存模型

所有权(Ownership)

深拷贝(deep copy)与浅拷贝(shallow copy)

堆上数据的拷贝:

即:一块内存在某个时间上只可以属于一个变量

栈中数据的拷贝:

Copy trait

拥有Copy trait的类型:

所有权与函数

例子

//以下代码会报错
fn main() {
    let s = String::from("hello");
    let i = 5;
    take_ownership(s);//s将所有权移交(move)给了take_ownership()中的some_string变量,s不可再被读取和操作
    makes_copy(i);//i将自己的副本传入了makes_copy(),i的所有权仍在自己手上

    println!("{}",s);//在此处程序会报错
    println!("{}",i);//i还是可以正常被读取使用的

}
fn take_ownership(some_string: String){
    println!("{}",some_string);
    //在此时some_thing变量的作用域马上结束,Rust会调用drop(),它引用的内存将会被free
}
fn makes_copy(some_number: i32){
    println!("{}",some_number);
    //此处却不会发生什么
}

返回值与作用域

fn main() {
    let k = String::from("kaka");
    let s1 = give_ownership();//give_ownership()中的s变量的所有权将会移交给s1
    let g = take_and_gives_back(k);//k变量的所有权将先回移交给a_string,a_strin会再将所有权移交回给g,而k已经不再有意义了
}
fn give_ownership() -> String {
    let s = String::from("hello");
    s//所有权移交给give_ownership()的接收者
}
fn take_and_gives_back(a_string: String) -> String {
    a_string//a_string的所有权来自于k的所有权,最后又将此所有权移交给函数接收者g
}

引用(Reference)和借用

引用(Reference)

例子:

fn main() {
    let k = String::from("kaka");
    let g = take_and_gives_back(&k);
    println!("{}",k);
}
fn take_and_gives_back(a_string: &String) -> usize {
    a_string.len()
}

可以看到程序正常运行,并没有报错,这是因为:

借用

如上个例子中:

可变引用的限制:

这样可以防止发生数据竞争,以下三种情况同时满足时,就会发生数据竞争:

Rust在编译时就会检查以上三种情况是否同时发生

另一个限制:

一个数据不可以同时拥有一个可变引用和一个不变的引用

悬空引用(Dangling Reference)

悬空指针(类似野指针):

一个指针引用了内存中的某个地址,而这块内存可能已经释放并分配给其他人使用了

例子:

//以下代码会报错
fn main() {
   dangle();
}
fn dangle() -> &String { //此处报错
    let  k = String::from("kaka"); 
    &k;
}

因为假使编译可以通过,那么在dangle()结束时,k变量就会被Drop(),那么返回的就是一个悬空引用(野指针),这是没有意义且危险的

引用的使用规则

以上两者只能满足之一

另一个规则为:

引用必须一直有效