做个备份
Rust
案例
猜数
use std::io;
use rand::Rng;
use std::cmp::Ordering;
fn main() {
let mut guess = String::new();
let secret_number = rand::thread_rng().gen_range(1, 101); // 1-100
println!("{}", secret_number);
loop {
io::stdin().read_line(&mut guess).expect("cant 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;
},
}
}
}
变量
const MAX_P: u32 = 100_000;
fn main() {
let x = 5;
let x = x ** 5;
println!("{}", x);
let spaces = " ";
let spaces = spaces.len();
println!("{}", spaces);
}
Tuple
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup;
println!("{} {} {}", x, y, z);
println!("{} {} {}", tup.0, tup.1, tup.2);
}
数组
fn main() {
let a = [1, 2, 3, 4, 5];
let months = [
"one",
"two",
];
// 数组类型 [类型; 长度]
let b: [i32; 5] = [1, 2, 3, 4, 5];
// 如果数组中每个元素都相同
// 相当于 let c = [3,3,3,3,3];
let c = [3; 5];
let one = months[0];
let two = months[1];
}
函数
fn main() {
another_function();
other_function(5);
let y = {
let x = 1;
x + 1
};
let five = five();
}
fn another_function() {
println!("the value is 5");
}
fn other_function(x: i32) {
println!("the value is {}", x);
}
fn five() -> i32 {
5
}
条件判断
fn main() {
let number = 5;
if number < 5 {
println!("less than 5");
} else if number > 5 {
println!("bigger than 5");
} else {
println!("equal 5");
}
// 这是因为 if 语句是一个表达式
let condition = true;
let number = if condition {
5 } else {
6 };
println!("The value of number is: {}", number);
}
循环
fn main() {
loop {
println!("hello world");
}
let mut count = 0;
let result = loop {
count += 1;
if count == 10 {
break count * 2;
}
};
println!("The result is {}", result);
let mut number = 3;
while number != 0 {
println!("{}", number);
number -= 1;
}
// 返回数组元素的迭代指针
let a = [1, 2, 3, 4, 5];
for element in a.iter() {
println!("The value is {}", element);
}
// 左闭右开
// rev() 能反转 range
for number in (1 .. 4).rev() {
println!("The value is {}", number);
}
}
所有权
- 所有权为了管理 heap 中的数据而生
- 所有权解决的问题
- 跟踪代码的哪些部分正在使用 heap 中的数据
- 最小化 heap 上的重复数据量
- 清理 heap 上未使用的数据以避免空间不足
所有权规则、内存与分配
String
- 字符串字面量不能修改
- String 类型的值可以修改
内存与分配
-
字符串字面值,在编译时就知道她的内容了,其文本内容是可以直接硬编码到最终的可执行文件里
- 速度快、高效
-
String 保存在 heap 中
-
Rust 中当某个值走出作用范围时,内存会立即自动交还给操作系统(通过自动调用 drop() 函数实现)
fn main() {
let s1 = String::from("Hello");
let s2 = s1; // 于是 s1 失效了
let s3 = s2.clone(); // 复制
// 针对 stack 上的不存在 move 这一回事
let x = 5;
let y = x;
}
拥有 Copy Trait
- 任何简单的标量的组合类型都可以是 Copy 的
- 任何需要分配内存或某种资源的都不是 Copy 的
- 一些拥有 Copy Trait 的类型
- 所有的整数类型
- bool
- char
- 所有的浮点类型
- Tuple ,如果其所有的字段都是 Copy 的
所有权与函数
- 在语义上,把值传递给函数和把值赋给变量是类似的
- 将值传递给函数将发生移动或复制
- 返回值与作用域
- 函数在返回值的过程中同样也会发生所有权的转移
- 一个变量的所有权总是遵循同样的模式
- 把一个值赋给其他变量时就会发生移动
- 当一个包含 Heap 数据的变量离开作用域时,它的值就会被 drop 函数清理,除非数据的所有权移动到另一个变量上
fn main() {
let s = String::from("Hello World");
take_ownership(s);
let x = 5;
makes_copy(x);
println!("x: {}", x);
}
fn take_ownership(some_thing: String) {
println!("{}", some_thing);
}
fn makes_copy(some_number: i32) {
println!("{}", some_number);
}
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");
some_string
}
fn takes_and_gives_back(a_string: String) -> String {
a_string
}
fn main() {
let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len();
(s, length)
}
引用与借用
-
把某一个变量借用为不可变引用后,就不能把变量借用为可变引用
-
引用允许使用某个值而不取得其所有权
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plPRJxna-1639451769486)(/Users/chenghaijie/Library/Application Support/typora-user-images/image-20211203224800474.png)]
-
不可以修改借用的东西
-
和变量一样,引用默认是不可变的,但当创建的是可变引用时则可以修改它
-
在特定作用域内,对某一块数据,只能有一个可变的引用
- 这样做的好处是可在编译时防止数据竞争
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()
}
fn main() {
let mut s1 = String::from("Hello");
let len = calculate_length(&mut s1);
println!("The length of {} is {}", s1, len);
}
fn calculate_length(s: &mut String) -> usize {
s.push_str(" world");
s.len()
}
切片
-
字符串字面值就是切片
-
切片是不持有所有权的数据类型
fn main() {
let mut s = String::from("Hello World");
let worldIndex = first_world(&s);
s.clear();
println!("{}", worldIndex);
}
fn first_world(s: &String) -> usize {
let bytes = s.as_bytes();
// enumerate 会将迭代结果包装成元祖
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
-
字符串切片是指向字符串中一部分内容的引用(左闭右开)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZRKcz00-1639451769487)(/Users/chenghaijie/Library/Application Support/typora-user-images/image-20211204085727364.png)]
fn main() { let s = String::from("Hello World"); let hello = &s[0..5]; let world = &s[6..]; let whole = &s[0..s.len()]; }
-
字符串字面值是不可变引用
-
有经验的开发者通常会把函数参数以及返回值设置为 &str ,因为这样能接受不同类型的参数
fn main() { let mut s = String::from("Hello World"); let worldIndex = first_world(&s[..]); let my_s = "Hello World"; let worldIndex = first_world(my_s); } fn first_world(s: &str) -> &str { let bytes = s.as_bytes(); // enumerate 会将迭代结果包装成元祖 for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[0..i]; } } &s[0..] }
-
其他类型的切片
fn main() { let a = [1, 2, 3, 4, 5]; let slice = &a[1..3]