rust所有权、切片、引用
给博客加了个二维码手机阅读,点标题后面就可以。
还有添加了图片全屏展示。
学习视频:B站
所有权
Rust最独特的特性,无需GC就可以保证内存安全。
所有程序运行时都必须管理使用计算机内存的方式:
- 垃圾收集
- 程序员显示分配和释放内存
- Rust:所有权系统管理内存
Rust需要更加关注栈内存和堆内存。stack vs heap。
所有权解决的问题:
- 跟踪代码哪些部分在使用heap的哪些数据
- 最小化堆上的重复数据量
- 清理heap未使用的数据
所有权规则:
- 每个值有一个变量,这个变量是值的拥有者
- 每个值同时只能有一个所有者
- 当所有者超出作用域时,将被删除
String类型内存和分配
String类型的值可以修改,而字符串字面值不能修改。(处理内存的方式不同)
- 字符串字面值编译时就知道内容,被硬编码到可执行文件。速度快,效率高
- String类型,heap上分配内存保存编译时未知的文本内容
Rust当拥有它的变量离开作用域后,会自动将内存归还给操作系统,如String会自动调用drop函数。
变量和数据交互方式
String:
不是浅拷贝,而是移动,s1失效了。
隐含原则:Rust不会自动创建数据的深拷贝。
深拷贝clone()
:
fn main() {
let s1 = String::from("hello");
// 深拷贝,正确
let s2 = s1.clone();
println!("{}",s1); // 正确
}
stack上的数据:复制,旧变量仍可使用
fn main() {
let a = 5;
let b = a;
println!("{} {}",a,b); // 5 5
}
Copy trait的类型
- 简单标量的组合
- 任何需要分配内存或资源的都不是copy trait
特殊情况:
Tuple,如果所有字段都是copy,那这个tupe就是copy的。
(i32, i32)
是(i32, String)
不是
函数参数传递
fn main() {
let s = String::from("Hello World");
take_ownership(s);
// 此时这里的s已经失效了
// println!("{}",s); // value moved
let x = 5;
makes_copy(x);
println!("{}",x);
}
fn take_ownership(some_string: String) {
println!("{}",some_string);
}
fn makes_copy(some_number: i32) {
println!("{}",some_number);
}
返回值和作用域
fn main() {
let s1 = gives_ownership();
let s2 = String::from("hjell");
let s3 = takes_and_gives_back(s2);
}
fn gives_ownership() -> String {
let s = String::from("hi");
s
}
fn takes_and_gives_back(s: String) -> String {
s
}
引用和借用
fn main() {
let mut s1 = String::from("hi");
let len = get_len(&mut s1);
// 在一块数据,只能有一个可变引用,编译时防止数据竞争
println!("{}: {}",s1,len)
}
fn get_len(s: &mut String) -> usize {
s.push_str("hi");
s.len()
}
可以通过创建新的作用域,来允许非同时创建多个可变引用。
{
let s2 = &mut s1;
}
let s3 = &mut s1;
切片
slice,不持有所有权。
demo:查找第一个空格
不切片:
fn main() {
// 查找第一个空格
let mut s = String::from("hi23 rae");
let wordIndex = first_world(&s);
println!("{}",wordIndex);
}
fn first_world(s: &String) ->usize {
let bytes = s.as_bytes();
for (i,&item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
切片:字符串切片是指向字符串中其中一部分内容的引用。
fn main() {
// 查找第一个空格
let mut s = String::from("hello world");
// let hello = &s[0..5];
// let world =&s[6..11];
let word = first_world(&s);
println!("{}",word);
}
fn first_world(s: &String) ->&str {
let bytes = s.as_bytes();
for (i,&item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..]
}