Rust的意义
1. 编译器会拒绝具有潜在bug风险的代码,减少了单元测试时间,便于大规模合作
2. Rust自身携带的工具: Cargo帮助管理依赖包+编译+测试,Rustfmt能够统一代码风格,Rust Language Server内含IDE
3. 面向系统开发者,速度与稳定性兼备
资源列表
书源码: https://github.com/rust-lang/book/tree/master/src
discord: https://discord.com/invite/rust-lang
安装、文档相关命令
rustup update
rustup self uninstall
rustup doc
Hello World!
1. 用rustc
fn main() { //main.rs println!("Hello, world!"); }
rustc main.rs
2. 用cargo
cargo new hello_cargo
cargo build
cargo build --release
cargo run
cargo check #确保代码能通过编译,但是不编译
简单示例:Guessing Game
use rand::Rng; use std::cmp::Ordering;//std::cmp下面的enum use std::io; fn main() { println!("Guess the number!"); let secret_number = rand::thread_rng().gen_range(1, 101); loop {//infinite loop println!("Please input your guess.");//println! is a macro let mut guess = String::new();//let 定义变量,mut 决定变量是否可变,String是变长UTF8编码字符串 io::stdin() .read_line(&mut guess)//mut 表示函数能够改变这个变量, &表示传递的是guess的引用,由于引用默认是immutatble,不可改变的,所以这里用&mut .expect("Failed to read line");//read_line返回的是io::Result,可能是Err或者Ok,res.expect在返回OK时获取OK内部包含的值,在返回Err的时候输出提示并crash,如果不expect,会编译时有Warning let guess: u32 = match guess.trim().parse() {//更改了guess的类型看,通过声明guess为u32,parse明确要转化为什么类型 Ok(num) => num, Err(_) => continue,//注意这里match错误处理 }; println!("You guessed: {}", guess); match guess.cmp(&secret_number) {//match由多个arm组成 Ordering::Less => println!("Too small!"),//Ordering::less是这个arm的pattern,如果被匹配上了,就运行后面的代码 Ordering::Greater => println!("Too big!"), Ordering::Equal => { println!("You win!"); break; } } } }
Cargo.toml中要加入依赖的crate:
[dependencies] rand = "0.5.5"//实际上是^0.5.5,即任意和0.5.5版本的public API匹配的版本
此时cargo是从registry(即crates.io的数据的拷贝中)获取的依赖包。生成的Cargo.lock文件确保了依赖包的版本不会因为重新build发生变化,除非手动upgrade(cargo update,获取新依赖包)。
变量
变量默认是immutable的,不能变更具体值,这样限制给程序带来了安全保障,有时不更改数据结构,而是直接新建或者拷贝一个类似的能够带来额外的安全保障。不过在变量声明时加上mut就能变成可写的变量。
rust同样支持const,那么immutable variable和const variable的差别是什么呢?
const MAX_POINTS: u32 = 100_000;
1. 显然,不需要在const上面使用mut,同时,普通变量的类型可以被某种程序上推测到,但是const是一定要声明类型的。
2. const变量可以在任何作用域声明,包括global scope。
3. const变量只能是一个不变的静态表达式计算的产物,而不能是一个函数调用或者必须要运行时才能确定的其他任何值。
使用const变量的好处-便于传达某个值的意义
Shadowing
变量Shadowing指用let声明一个新的、类型可能不同的变量替代一个旧的同样名字的变量。旧的is shadowed by新的。实际上,这两个变量除了名字相同,可以没有其他联系。这样做的好处是能够减少无意义的变量命名,比如a, a_str。
let spaces = 123; let mut spaces = " ";//That is ok! println!("Hello, world!");
数据类型
Rust是静态类型语言,需要能够在编译阶段确定所有变量的类型。Rust会尽量推断变量类型,如果无法推断,就会编译时报错。
let guess = "42".parse().expect("Not a number!"); | ^^^^^ consider giving `guess` a type
Scalar types
Integers, Floating-point, Booleans, Chararcters。
Integers: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize isize和usize与机器环境有关,如果是32位环境,长度32,64位环境长度64
输入方式: 0xff, 0o77, 0b11111_0000, b'A'
注意: Integer Overflow具有如下设置:当debug选项编译后,如果运行时出现Overflow会panic,但是在release下则会自动wrap(具体Wrap方法在Wrapping中实现)
Floating point: f32, f64
Char Type: 注意区分与u8的差别。此外,U+0000到U+D7FF到U+E000到U+10FFFF都能用char直接表示。Accented letters; Chinese, Japanese, and Korean characters; emoji; and zero-width spaces are all valid char values in Rust
组合类型-tuples and arrays
Tuple
fn main() { let tup: (i32, f64, u8) = (500, 6.4, 1); let (x, y, z) = tup;//destructuring let five_hundred = x.0;//访问tuple内元素 let six_point_four = x.1; let one = x.2; }
Array
let a: [i32; 5] = [1, 2, 3, 4, 5]; let a = [3; 5];//[初始值;个数] let first = a[0];
函数
默认使用snake case方式(即使用小写和_)来写函数名和变量名。
fn main() { another_function(5, 6); } fn another_function(x: i32, y: i32) {
let y = {let x = 3;x + 1};//括号内是一个expression println!("The value of x is: {}", x); println!("The value of y is: {}", y);
5 //如果加一个分号,就变成了statement,就不能直接作为返回值,会报错 }
注释
基本的注释//
还有专用于文档生成的注释
控制流
If
fn main() { let condition = true; let number = if condition { 5 } else { 6 }; if number % 4 == 0 { println!("number is divisible by 4"); } else if number % 3 == 0 { println!("number is divisible by 3"); } else { println!("number is not divisible by 4, 3, or 2"); } println!("The value of number is: {}", number); }
Loop
fn main() { let mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2;//result = counter * 2, break语句返回了值 } }; loop { println!("again!"); } println!("The result is {}", result); }
While
fn main() { let a = [10, 20, 30, 40, 50]; let mut index = 0; while index < 5 { println!("the value is: {}", a[index]); index += 1; } for element in a.iter() {//iteration println!("the value is: {}", element); } for number in (1..4).rev() {//rev: reverse the range println!("{}!", number); } }