Rust底座基础-权概念

文摘   2024-11-29 10:48   美国  

点击上方蓝字 江湖评谈设为关注/星标




前言

Rust三大权概念,锁死了类似于不安全代码造出的内存怪异等各种现象,以确保万无一失的安全代码构建。这就分别包括了:所有权,借用权,生命周期权。本篇分别看下。

一.所有权:每个值都有一个唯一的所有者,且每次只能有一个所有者。当所有者超出作用域时,值将被自动销毁。

fn main() {    let s1 = String::from("Hello"); // `s1` 是 `String` 的所有者    let s2 = s1; // `s2` 获得所有权,`s1` 不再有效
// println!("{}", s1); // 编译错误:`s1` 不再有效 println!("{}", s2); // 正确:`s2` 拥有所有权}

在这个示例中,s1 和 s2 都是 String 类型,但因为所有权转移,s1 被移除,不能再使用。Rust 的所有权系统会在编译时检查这些所有权转移,从而避免内存错误。

二.借用权:借用允许你在不获得所有权的情况下访问数据。借用有两种形式:借用数据能修改,借用数据不能修改。

1.借用能修改

fn main() {    let mut s1 = String::from("Hello");    let s2 = &mut s1; // 可变借用    s2.push_str(", world!"); // 通过 `s2` 修改 `s1`    println!("{}", s2); // 输出:Hello, world!}

2.借用不能修改

fn main() {    let s1 = String::from("Hello");    let s2 = &s1; // 不可变借用    println!("{}", s2); // 正确:通过 `s2` 访问 `s1` 的内容    println!("{}", s1); // 正确:`s1` 仍然有效}

注意,在同一时间,你只能拥有一个可变借用,不能同时有可变借用和不可变借用。这是 Rust 用来保证数据一致性的规则。

3.借用规则冲突


fn main() {    let mut s1 = String::from("Hello");    let s2 = &s1; // 不可变借用    let s3 = &mut s1; // 编译错误:不能同时拥有不可变借用和可变借用}

在上面的例子中,s2 是对 s1 的不可变借用,而 s3 是对 s1 的可变借用。Rust 会禁止这种同时借用的行为,避免数据竞争。

三.生命周期权:Rust 用来追踪引用在程序中的有效期的机制。它确保引用不会在其指向的数据销毁后继续存在。生命周期通常由编译器自动推导,但在某些情况下,你需要显式地指定生命周期。

fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {    if s1.len() > s2.len() {        s1    } else {        s2    }}
fn main() { let string1 = String::from("Hello"); let string2 = String::from("World"); let result = longest(&string1, &string2); // 生命周期标注 println!("The longest string is: {}", result);}

在这个例子中,'a 是生命周期标注,表示 s1 和 s2 的生命周期相同,并且返回值的生命周期也与它们相同。Rust 编译器根据这些标注推导出所有引用的生命周期,确保没有悬挂引用。

生命周期推导,在很多情况下,Rust 可以推导出生命周期,而你不需要显式地标注它们。

示例:生命周期推导

fn main() {    let string1 = String::from("Hello");    let string2 = String::from("World");    let result;        {        let s1 = &string1;        let s2 = &string2;        result = longest(s1, s2); // Rust 自动推导生命周期    }
println!("The longest string is: {}", result); // 编译错误:生命周期不匹配}

在这个例子中,s1 和 s2 都是局部变量,当它们超出作用域时,result 变得无效,因为 result 的生命周期依赖于 s1 和 s2 的生命周期,而它们已经不再有效。

四.组合示例:所有权、借用和生命周期

fn main() {    let string1 = String::from("Hello");    let string2 = String::from("World");
let result = longest(&string1, &string2); println!("The longest string is: {}", result);}
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 }}

在这个示例中:s1 和 s2 是对字符串的引用,它们的生命周期由 Rust 编译器推导出来。longest 函数返回一个引用,它的生命周期与传入的参数相同,这就是生命周期 'a 的作用。

总结

所有权:Rust 的内存管理通过所有权系统确保每个值有且只有一个所有者,所有者超出作用域时会自动清理内存。

借用:Rust 支持通过不可变借用和可变借用来借用数据,同时保证了没有数据竞争和内存错误。

生命周期:生命周期帮助 Rust 确保引用不会超过数据的有效期,避免了悬挂引用问题。

这些特性结合起来,使得 Rust 能在保证内存安全和数据一致性的同时,避免垃圾回收的性能开销,提供了零成本的抽象和高效的系统编程能力。

往期精彩回顾

Rust会取代C++吗?

Rust安全指针,如何回收堆?

Rust奇妙的玩出天际的花活儿


关注公众号↑↑↑:江湖评谈 

江湖评谈
记录,分享,自由。
 最新文章