rust学习-所有权
Rust 的所有权系统是其最大的特色之一,也是 Rust确保内存安全和避免空指针、数据竞争等错误的关键机制,所有权系统的核心概念包括所有权、引用和生命周期
所有权
rust中每个值都有一个与其相关联的变量,称为其所有者,所有权遵循以下规则:
- 每个值都有一个所有者
- 值在任何时刻都只能有一个所有者
- 当所有者离开作用域时,该值将被丢弃
{
let s = String::from("hello"); // s 进入作用域
// 使用 s
} // s 离开作用域,被丢弃
在这个示例中,s 是 String::from(“hello”) 的所有者,当 s 离开作用域时,String 被自动丢弃,释放其占用的内存
移动所有权
当将一个值赋给另一个变量时,所有权会被转移,原始变量不再有效
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权被转移给 s2
// println!("{}", s1); // 这里会报错,因为 s1 已经不再有效
println!("{}", s2); // 正确,s2 拥有字符串
}
在这个示例中,s1 的所有权被转移给 s2,因此 s1 在转移后不能再使用
复制和克隆
对于简单数据类型,如整数和布尔值,Rust 会自动复制它们,因此不会发生所有权转移
let x = 5;
let y = x; // x 被复制,y 也等于 5
对于复杂类型,如 String,需要显式地克隆数据
let s1 = String::from("hello");
let s2 = s1.clone(); // 克隆 s1 的数据
引用
引用可使用变量的值而不转移所有权,引用必须是 immutable(不可变)的,除非显式指定为 mutable(可变)
let s1 = String::from("hello");
let len = calculate_length(&s1); // 传递引用
println!("The length of '{}' is {}.", s1, len);
fn calculate_length(s: &String) -> usize {
s.len()
}
在这个示例中,&s1 是一个对 s1 的引用,calculate_length 函数接受一个 &String 参数
可变引用
要修改通过引用传递的值,需要使用可变引用
let mut s = String::from("hello");
change(&mut s);
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
在这个示例中,&mut s 是一个可变引用,允许在 change 函数中修改 s 的值
生命周期
生命周期是 Rust 编译器用于确保引用总是有效的机制,编译器会检查引用的生命周期,确保它们不会超过所引用数据的生命周期
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
在这个示例中,'a 是一个生命周期参数,表示返回的引用至少和传入的引用一样长
所有权和函数
函数可以接受所有权或引用作为参数
接受所有权
fn takes_ownership(some_string: String) {
// some_string 现在是这个函数的局部变量
println!("{}", some_string);
}
fn main() {
let s = String::from("hello");
takes_ownership(s);
// s 现在不再有效
}
接受引用
fn calculates_length(s: &String) -> usize {
s.len()
}
fn main() {
let s = String::from("hello");
let length = calculates_length(&s);
println!("The length of '{}' is {}.", s, length);
}
返回值和作用域
函数可以返回值的所有权
fn gives_ownership() -> String {
let some_string = String::from("hello");
some_string // 返回 some_string 的所有权
}
fn main() {
let s = gives_ownership();
println!("{}", s);
}
注意事项
- 避免悬挂引用:不要返回对局部变量的引用,因为局部变量在函数结束时会被丢弃
fn bad() -> &String {
let s = String::from("hello");
&s // 错误,s 在函数结束时被丢弃
}
- 不可变引用和可变引用的规则:
- 在同一作用域内,只能有多个不可变引用或一个可变引用
- 不能在有可变引用的同时有不可变引用
let mut s = String::from("hello");
let r1 = &s; // 不可变引用
let r2 = &s; // 另一个不可变引用
// let r3 = &mut s; // 错误,已有不可变引用
println!("{} and {}", r1, r2);
drop(r1); drop(r2);
let r3 = &mut s; // 可变引用
println!("{}", r3);
- 生命周期注解:对于复杂的情况,可能需要显式指定生命周期
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
- Deref 自动引用转换:Rust 的自动解引用(deref coercions)可以隐式地将引用转换为其他类型的引用
struct Person {
name: String,
age: u8,
}
fn print_name(p: &Person) {
println!("Name: {}", p.name);
}
fn main() {
let person = Person { name: String::from("Alice"), age: 30 };
print_name(&person);
}
原文地址:https://blog.csdn.net/weixin_42333247/article/details/145307662
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!