Rust入门笔记
记录在https://course.rs 上学习Rust中的一些知识点
其实之前断断续续也看过一段Rust了,但是可惜总是没办法连续学习。可能这几天工作任务不忙,就看一看。过几天忙了就断了。等下次再去看的时候,可能就忘了很多东西,导致我一直在不断重复地学习入门的知识,就感觉效率很低。
所以我就想着,对抗遗忘最好的方法,一个是用起来,再一个就是记下来。目前用起来有些难度,所以就先记下来。这样或许我再因为时间关系中断了学习的时候,下一次就不用从头学起,直接看我记下来的关键点就可以了。其实我之前写React源码的介绍,很大程度上也是在防止自己看过后又忘记。
由于有js和c的基础,因此主要记录一些Rust比较独特的特性,或者和前两者当中相似却不同的点。
2.2 基本类型
- 默认let声明的变量不可变。带mut声明的变量才是可变的。
- ()单元类型,唯一的值是(),含义可以理解为“没有意义”。
- 表达式和语句。这是Rust比较有意思的点,语句是没有返回值的。
- 就比如
let a=8;不管在js还是Rust里,都是个语句。但是js里,这个语句的值是8,而Rust里它没有返回值。 a+1在Rust里是个表达式,有返回值。但是a+1;是语句,没有返回值。- 语句一定以分号结尾。可以声明变量,也可以是普通表达式+分号结尾。
- 就比如
- 函数返回值:最后一行如果是表达式,这个表达式的值就是返回值。前提是声明了函数的返回类型。在未声明函数返回类型的场景下,不管最后表达式是什么值,都会返回()。并且切记表达式没有分号。
2.3 所有权和借用
这部分是Rust主要区别于其他语言的特点。
对于未实现
Copy特征的类型(如String类型),复制操作会移动所有权。
例如1
2
3
4let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1); // 报错,s1已经失去所有权我理解为,堆上的这个变量只能被一个指针拥有(引用除外),依赖这个指针的状态来控制内存是否要被释放,避免被重复释放内存等内存的不安全操作。
可以用
s1.clone()方法深拷贝,避免所有权产生转移&x获取堆变量x的引用,再通过*来解引用,取到变量的值
例如1
2
3
4
5
6
7
8
9
10
11fn main() {
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()
}
传递引用不会影响所有权。
此处的
s.len()还涉及到了自动解引用。因为s本身是个引用,&mut x获取x的可变引用,才可以通过引用修改值。不可变变量,不可获取可变引用
可变引用同时只能存在一个。可变引用的作用域从定义他开始,到最后一次使用它结束。所以可以理解为,一旦对同一个变量定义了一个新的可变引用,那么后面的代码中前一个可变引用就不能再被使用了
例如1
2
3
4
5
6
7
8
9
10
11// 注释掉一行代码让它工作
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
r1.push_str("world");
let r2 = &mut s;
r2.push_str("!");
// println!("{}",r1); 注释掉这一行,这样r1和r2两个引用的作用域就没有重合了
}可变引用和不可变引用不能同时存在,类似上面一条。当不可变引用后面还要用到的时候,就不能定义可变引用。
对于没实现
Copy特征的类型,试图通过解引用取值,并且再赋值去转移所有权会报错
例如1
2
3
4let s = String::from("hi");
let r = &s;
let v = *r; // 报错很多方法的调用也涉及到引用的传递,例如
1
2let mut r = String::from("hi");
r.push_str("!");String::push_str其实会获取r的可变引用
尤其要注意这种隐藏的产生引用,和第4点中可变引用同时存在的问题ref x、ref mut x和&x、&mut x功能类似,用于解构赋值等模式匹配场景获取引用(解构赋值的时候没有合适的地方去写&)