Chapter2
let 定义变量,默认不可变,可变变量需要用 mut 关键字。
强类型推导,会根据等号右边结果或者后文自动推导变量类型。使用冒号可以定义类型。Rust 在编译的时候就必须知道变量的类型。
1 2
| let num: i32 = 10; let num: u32 = 10;
|
宏println!
用于输出,{}
用于填入此参数,在大括号中填数字可以分组。
1
| println!("cout {0}, {0}, {1}", a, b);
|
有些函数的返回值为Rusult
,有Ok
, Err
两种,使用expect
函数可以在错误时输出信息,但是程序仍然会崩溃。使用match
可以优美(网上这么说的)的在错误时采取其他的行为从而使程序继续。
1 2 3 4 5 6 7 8
| io::stdin().read_line(&mut num).expect("Failed to read line");
match io::stdin().read_line(&mut num) { Ok(num) => num, Err(_) => ..., };
|
猜数游戏:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| use rand::Rng; use std::cmp::Ordering; use std::io;
fn main() { let secret_number = rand::thread_rng().gen_range(1..=100);
loop { println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, };
match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => { println!("You win!"); break; } } }; }
|
Chapter3
常量不等于不可变的变量,const 声明,必须指定类型。
1
| const MAX_NUM: i64 = 20070206;
|
Shadow 机制,同名变量后者会隐藏前者。
1 2 3 4 5 6 7
| let mut num1 = 10; num1 = 20;
let mut num1 = 10; let num1 = "dmx20070206";
|
Rust 的整数类型:
位长度 |
有符号 |
无符号 |
8 bit |
i8 |
u8 |
16 bit |
i16 |
u16 |
32 bit |
i32 |
u32 |
64 bit |
i64 |
u64 |
128 bit |
i128 |
u128 |
arch |
isize |
usize |
不同进制:0x, 0o, 0b。任何进制都可以用 _ 分割。i32 为默认类型。 |
|
|
Rust 的浮点数类型:
f32, f64, IEEE-754 标准。f64 为默认类型。
Rust 的布尔类型:略
Rust 的字符类型:
表示一个 Unicode 字符,占用 4 个字节。
Rust 中的 Tuple:
1 2
| let num: (u32, char, f32) = (10, '😅', 1.5); println!("{}, {}, {}", num.0, num.1, num.2);
|
Rust 中的 数组:
1 2 3 4 5 6 7
| let num: [f64; 3] = [1.1, 1.2, 1.3]; println!("{}, {}, {}", num[0], num[1], num[2]);
let num = [3; 5]; println!("{}, {}, {}, {}, {}", num[0], num[1], num[2], num[3], num[4]);
|
Rust 中的表达式类型:
1 2 3 4 5
| let x = { let num = 10; num };
|
Rust 中的函数,用fn
关键字,参数必须声明类型,返回值用->
符号定义,函数默认返回最后一个表达式,可以隐藏return
:
1 2 3 4 5 6 7 8
| fn function(x: u32) -> u32 { x + 1 }
fn function(x: u32) -> u32 { return x + 1; }
|
Rust 中的 if-else:
1 2
| let condition = true; let num = if condition { 10 } else { 20 };
|
Chapter 4
所有权是 Rust 中很重要的概念,所有程序在运行时都必须管理它们使用计算机内存的方式。
- 有些语言自带 GC,程序运行时会一直搜索已经不用的内存
- 有些语言需要程序员显式的申请和释放内存
- Rust 通过一个所有权系统来管理内存,其中包含一组编译器在编译时检测的规则
Rust 中,可以向 Stack 和 Heap 申请内存。Stack 只能存放定长的数据,Heap 可以存放变长的数据。很明显,计算机访问 Stack 上的数据快于 Heap,因为从 Stack 获取数据一定是栈顶,并且 Stack 中各个数据离得近。
String 类型是典型的变长数据类型,它只能存放于 Heap 上。通过from
方法可以通过字符串常量创建一个 String 类型,它存放于 Heap 上,所以它是可变的。
Drop, Move, Copy, Clone
Drop 清理规则:
- 当一个数据离开作用域时,立即释放它占用的内存
- 对于失效(Moved)的变量,不会释放它占用的内存
- 对于 Stack 上的简单数据,不需要 Drop
- 对于 Heap 上的数据,需要 Drop
Move 移动规则:
- 对于 Stack 数据,等同于 Copy
- 对于 Heap 数据,前者将被失效
1 2 3 4 5 6 7 8 9 10
| let num1 = 10; let num2 = num1;
let s1 = String::from("dmx"); let s2 = s1;
|
Copy 拷贝规则:
- 如果变量一部分创建了 Drop,那么该变量不能拥有 Copy
- Copy 类型的变量一般存放于 Stack 上,不需要额外的 Drop 操作
1 2
| let num1 = 10; let num2 = num1;
|
Clone 克隆规则:
- 使用 clone 方法,可以实现深拷贝?
- 在 Heap 上开辟新的一块内存
1 2
| let s1 = String::from("dmx"); let s2 = s1.clone();
|
函数的参数传递中所有权的转移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| fn main() { let s = String::from("hello");
takes_ownership(s);
let x = 5;
makes_copy(x);
}
fn takes_ownership(some_string: String) { println!("{}", some_string); }
fn makes_copy(some_integer: i32) { println!("{}", some_integer); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| fn main() { let s1 = gives_ownership();
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2); }
fn gives_ownership() -> String { let some_string = String::from("hello");
return some_string; }
fn takes_and_gives_back(a_string: String) -> String {
a_string }
|
Rust 中的引用和租借
引用是一种“借”所有权的过程,例如下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12
| fn 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() }
|
借用后不可以修改原数据,除非用mut
关键字修饰,如下:
1 2 3 4 5 6 7 8
| fn main() { let mut s1 = String::from("dmx");
let s2 = &mut s1;
s2.push_str("20070206"); println!("{}", s2); }
|
一个变量的某时刻的全部有效引用必须满足如下规则:
- 有至多一个可变引用
- 有若干个不可变引用
- 引用必须一致有效
同时,在 Rust 中不允许悬空引用,如下:
1 2 3 4 5 6 7 8 9 10 11
| fn main() { let reference_to_nothing = dangle(); }
fn dangle() -> &String { let s = String::from("hello");
&s }
|