Rust所有权(非常重要)

1.其他语言的内存管理,在C/C++中,开发者需要手动释放申请的内存资源。在Java(jvm) 中,JVM采用了垃圾回收的机制,但是这样会降低运行时的效率,并非实时的,所以JVM会尽可能少的回收,这很矛盾,所以还是不好,而 Rust 对栈内存和堆内存一视同仁,超出作用域一律自动释放。Rust 的这个特点在兼顾性能的情况下、有效的减少了代码量和内存泄漏隐患。。
2.Rust所有权规则:每一个值都有一个变量,称为其所有者,一次只能有一个所有者,当所有者不在程序运行范围内的时候,该值将会被删除。
3.变量范围:rust以大括号为界,超出范围则会被回收。申请长度不确定的内存时,会使用到堆这种结构。
4.变量与数据的交互方式:第一种是移动(move),第二种是克隆(clone)。

移动(move): 多个变量可以在 Rust 中以不同的方式与相同的数据交互

let x=3;    let y=x;

这里的数据是基本数据类型,所以不需要存到堆中,只在栈中复制和移动。
基本数据类型:
1.所有整数类型,例如 i32 、 u32 、 i64 等。
2.布尔类型 bool,值为 true 或 false 。
3.所有浮点类型,f32 和 f64。
4.字符类型 char。
5.仅包含以上类型数据的元组(Tuples)。
如果发生的情况在堆里面,就会不一样:

let s1=String::from("hello"); 
let s2=s1;

此处hello需要存在堆里面,后面释放的时候,并不会释放两次,因为s2=s1时,s1已经无效了,后面无法使用。
在这里插入图片描述
克隆(clone): 但如果需要将数据单纯的复制一份以供他用,可以使用数据的第二种交互方式。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}, s2 = {}", s1, s2);
}

这里释放资源的时候,会被当成两个资源释放。

5.函数的所有权机制
fn main() {
    let s = String::from("hello");
    // s 被声明有效

    takes_ownership(s);
    // s 的值被当作参数传入函数
    // 所以可以当作 s 已经被移动,从这里开始已经无效

    let x = 5;
    // x 被声明有效

    makes_copy(x);
    // x 的值被当作参数传入函数
    // 但 x 是基本类型,依然有效
    // 在这里依然可以使用 x 却不能使用 s

} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放


fn takes_ownership(some_string: String) {
    // 一个 String 参数 some_string 传入,有效
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    // 一个 i32 参数 some_integer 传入,有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放

也就是说,如果函数变量当作参数传入函数,他和移动的效果是一样的。

6.函数返回值的所有权机制
fn main() {
    let s1 = gives_ownership();
    // gives_ownership 移动它的返回值到 s1

    let s2 = String::from("hello");
    // s2 被声明有效

    let s3 = takes_and_gives_back(s2);
    // s2 被当作参数移动, s3 获得返回值所有权
} // s3 无效被释放, s2 被移动, s1 无效被释放.

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    // some_string 被声明有效

    return some_string;
    // some_string 被当作返回值移动出函数
}

fn takes_and_gives_back(a_string: String) -> String { 
    // a_string 被声明有效

    a_string  // a_string 被当作返回值移出函数
}

被当作函数返回值的变量所有权将会被移动出函数,并返回到调用函数的地方,而不会被无效释放。

7.引用(reference)和租借(borrow)、

引用其实可以当成是指针,是变量的间接访问方式

fn main(){
let s1=String::from("hello");
let s2=&s1;
println!("s1 is {},s2 is {}",s1,s2);
}

这里的s1并不会被无效,s1个地址,它指向堆中的量,s1把地址给s2,s2指向s1。
在这里插入图片描述
记住这张图,s2=&s1。。当然在函数中传递引用参数,也是和这里一样的效果。
引用不会获得值的所有权,引用只是租借值的所有权。在引用之后s2=&s1,如果s3=s1,也就是将s1移动到s3,这时s2就无法租借s1而失效,需要重新租借s3。
同时,也不可以租借之后对值进行修改,这个和租房子一个道理,未经房东允许,不可以改变房子。
但是,也可以房东允许你装修:

fn main(){
let mut s1=String::from("run");
let s2=&mut s1;
s2.push_str("oob");
println!("{}",s2);
}

这里的&mut修饰的是可变的引用类型。
提出一个很重要的概念:同时写内存造成数据不一致的问题。
可变引用不允许多重引用,但是不可变引用可以。

let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);

这段代码有问题,因为多重可变引用了s。而rust对于这种设计就是出于对并发状态下发生数据访问碰撞的考虑,防止同时写进行修改数据造成数据的不一致性。

8.悬垂引用(dangling reference)

定义:指的是那种没有实际指向一个真正能访问的数据的指针(注意,不一定是空指针,还有可能是已经释放的资源)。这个就是C语言里面说的“野指针”,任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
在Rust语言里面不允许出现,如果有,编译器会发现它。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值