Rust学习笔记(2)—— 编程基础概念, 变量、数据类型、流程控制 (2024-06-23 更新)
本文的具体代码在这里
通过一个猜数字游戏掌握 rust
的基础语法 1 cargo new guess && cd guess
定义用户输入的数字变量 1 2 3 4 5 6 7 8 9 10 11 fn main () { println! ("guess the number!" ); let mut guess = String ::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line" ); let guess:u32 = guess.trim().parse(); }
rust 是函数式编程语言, 大多数变量在函数式编程中, 是变量不可变
的, 因为在函数中变量传入过程中, 确保变量的不可变性, 是函数式编程的一大特性. 所以 rust
的变量默认是不可变的, 反其道而行, 如果要将其设置为可变, 则要加上 mut
关键字
判断用户输入合法性 match
上面用户的输入有可能出现非数字的情况, 所以需要判断用户输入合法性,使用 match
语句, match
是函数式编程语言特有的语法
match
语法很强大, 我们先暂时把 Err 的情况统一处理为 0
1 2 3 4 5 6 7 let guess: u32 = match guess.trim().parse() { Ok (num) => num, Err (_) => { println! ("Please type a number!" ); 0 } };
处理随机数
我们生成一个随机数, 利用第三方的 rand
库
在 Cargo.toml
的依赖里添加: rand = "^0.8.5"
再在命令行运行 cargo build
命令, 自动安装依赖
1 2 [dependencies] rand = "^0.8.5"
并将其他代码包裹在 loop
循环里, 相当于其他语言的 whlie (true) {}
将上面 Err()
的逻辑改为 continue
, 如果用户猜错, 则继续猜, 不会跳出循环
1 2 3 4 5 6 7 8 9 10 11 use rand::Rng;fn main () { let secret_number = rand::thread_rng().gen_range(1 ..=100 ); loop { } }
比较数字的大小 引入 cmp
的 Ordering
库, 将上面随机生成的 secret_number
和用户输入的 guess
进行比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 use std::cmp::Ordering;fn main () { loop { match guess.cmp(&secret_number) { Ordering::Less => println! ("Too small!" ), Ordering::Greater => println! ("Too big!" ), Ordering::Equal => { println! ("You win!" ); break ; } } } }
最后, 贴出完整代码:
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 std::io;use rand::Rng;use std::cmp::Ordering;fn main () { println! ("guess the number!" ); let secret_number = rand::thread_rng().gen_range(1 ..=100 ); loop { 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 }; println! ("guess: {guess}" ); match guess.cmp(&secret_number) { Ordering::Less => println! ("Too small!" ), Ordering::Greater => println! ("Too big!" ), Ordering::Equal => { println! ("You win!" ); break ; } } } }
编程基础概念在 Rust
中的体现 变量
1 2 3 4 5 6 7 8 let mut x:i32 = 5 ;println! ("x value is {x}" );x = 6 ; println! ("x value is changed: {x}" );const COUNT: u32 = 1_000_000 ;println! ("COUNT value is {COUNT}" );
变量遮蔽(variable shadowing),同一个作用域内,允许对同一变量名进行二次定义
这样做的好处是方便,坏处是后期代码量大会使得代码难以维护,所以使用时应谨慎
1 2 3 4 5 let y: u32 = 7 ;println! ("y value is {}" , y);let y: &str = "eight" ;println! ("y value is changed: {}" , y);
数据类型 Intergers 分为有符号(i)和无符号(u):
Length
Signed
Unsigned
8-bit
i8
u8
16-bit
i16
u16
32-bit
i32
u32
64-bit
i64
u64
128-bit
i128
u128
arch
isize
usize
其取值范围分别是:2 的 8、16、32、64、128 次方
Signed
的数由于有负数的取值范围,所以比 Unsigned
取值范围减半
Type
Range
i8
-128~127
u8
0~255
i16
-32768~32767
u16
0~65535
i32
-2147483648~2147483647
u32
0~4294967295
i64
-9223372036854775808~9223372036854775807
u64
0~18446744073709551615
i128
-170141183460469231731687303715884105728~170141183460469231731687303715884105727
u128
0~340282366920938463463374607431768211455
进制: | Number literals | Example | | :–: | :–: | | Decimal | 98_222 | | Hex | 0xff | | Octal | 0o77 | | Binary | 0b1111_0000 | | Byte (u8 only) | b’A’ |
Floating 1 2 let x1 = 2.45 ; println! ("{}" , x1);
Boolean 1 2 let t = false ;println! ("{}" , t);
Charactor (字符型) 1 2 3 4 5 6 let ch = 'z' ;println! ("char z: {}" , ch); let z_char: char = 'ℤ' ; println! ("char z: {}" , z_char); let heart_eyed_cat = '😻';println! ("heart_eyed_cat: {}" , heart_eyed_cat);
tuple (元组)
1 2 3 4 5 6 7 8 9 let tup1: (&str , i32 , f32 ) = ("let's get Rusty!" , 1_000_000 , 0.45 );let (channel, sub_count, float_num) = tup;println! ("{} {} {}" , channel, sub_count, float_num); let sub_count: i32 = tup.1 ;println! ("sub_count: {}" , sub_count);
Array 1 2 3 4 let arr = [1 , 2 , 3 , 4 , 5 ];let arr1: [i32 ; 5 ] = [1 , 2 , 3 , 4 , 5 ];
Funtion
1 2 3 4 5 6 7 fn main () { my_function(12 , 34 ); } fn my_function (x: i32 , y: i32 ) -> i32 { println! ("my function: {}, y: {}" , x, y); }
函数返回值,可省 return
关键字,且返回的语句或变量无需加 ;
函数如有返回值,则须用 ->
定义返回值类型
1 2 3 4 5 6 7 8 fn main () { let result = my_function(12 , 34 ); println! ("result: {}" , result); } fn my_function (x: i32 , y: i32 ) -> i32 { x + y }
Control Flow if-else
1 2 3 4 5 6 7 8 let number: i32 = 5 ;if number < 10 { println! ("1 true" ); }else if number < 22 { println! ("2 true" ); }else { println! ("false" ); }
1 2 let condition: bool = true ;let num:i32 = if condition { 1 } else { 2 };
while
1 2 3 4 5 6 7 8 let mut n = 3 ;while n != 0 { println! ("{}!" , n); n -= 1 ; }
loop
和 while 循环有点类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 loop { println! ("again!" ); break } let mut counter = 0 ;let loop_result = loop { counter += 1 ; if counter == 10 { break counter; } }; println! ("loop_result: {}" , counter);
for
1 2 3 4 5 6 7 let arr_for = [11 ,22 ,33 ,44 ,55 ];for item in arr_for.iter() { println! ("the arr value is: {}" , item); }
类似 python
的 range
和 scala
的 Range
,在rust
里使用..
表示数值范围:
..
的取值范围包括开始值,不包括终止值:
1 2 3 4 5 6 for value in 1 ..4 { println! ("{}!!" , value); }