rust权威指南笔记(一)

第1章 入门指南

main.rs

fn main() {
    println!("Hello, world!");
}

编译运行

rustc main.rs
Windows: .\main.exe Linux: ./main

使用Cargo构建和运行项目

cargo new 项目名 创建项目
cargo build 编译
cargo run 编译并运行
cargo check 检查代码是否正确,不生成可执行文件
cargo build --release 编译并优化,生成可执行文件
cargo clean 清理编译生成的文件
cargo doc 生成文档


第2章 编写一个猜数游戏

main.rs

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    println!("猜一个数!");
    let secret_number = rand::thread_rng().gen_range(1,101);
    //println!("秘密数是:{}", secret_number);
    loop {
        println!("请输入一个1-100之间的数:");
        let mut guess = String::new(); //mut表示guess是可变的
        io::stdin().read_line(&mut guess).expect("读取失败");
        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };
        println!("你输入的数是:{}", guess);
        match guess.cmp(&secret_number) {
            Ordering::Less => println!("太小了"),
            Ordering::Greater => println!("太大了"),
            Ordering::Equal => {
                println!("恭喜你猜对了!");
                break;
            }
        }
    }
}

Cargo.toml

[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"

[dependencies]
rand = "0.3.14"

第3章 通用编程概念

变量和可变性

变量默认是不可变的,使用mut关键字可以声明可变变量

变量与常量

const MAX_POINTS: u32 = 100_000;

使用const关键字声明常量,并且其类型必须被标注

常量可以被声明在任何作用域中,甚至包括全局作用域

你只能将常量绑定到一个常量表达式上,而无法将一个函数的返回值,或其他需要在运行时计算的值绑定到常量上

变量隐藏

可以使用相同的变量名来隐藏之前声明的同名变量。这种情况下,第一个变量被第二个变量”隐藏”了。

  • 错误
let mut guess = String::new(); //mut表示guess是可变的
io::stdin().read_line(&mut guess).expect("读取失败");
guess: u32 = match guess.trim()parse().expect("转换失败");

warnning:可变变量可以改变值但不能改变类型

let x = 5; 
x = x + 1;

warnning:不可变变量不可以改变值,但可以隐藏变量

  • 正确
let mut guess = String::new(); //mut表示guess是可变的
io::stdin().read_line(&mut guess).expect("读取失败");
let guess: u32 = match guess.trim()parse().expect("转换失败");
let x = 5; 
let x = x + 1;

Rust与Python变量区别:

  • 类型系统
    Python 是动态类型语言,变量类型可以随时改变
    Rust 是静态类型语言,需要在编译时就确定类型,比如 let guess: u32

  • 变量声明
    Python 直接赋值即可:guess = “123”
    Rust 需要用 let 关键字 Rust 默认变量是不可变的,需要 mut 关键字才能修改

隐藏机制与mut的一个区别:

由于重复使用let关键字会创建出新的变量,所以我们可以在复用变量名称的同时改变它的类型,mut变量不可以改变类型

数据类型

Rust是一门静态类型语言,这意味着它在编译程序的过程中需要知道所有变量的具体类型。在大部分情况下,编译器都可以根据我们如何绑定、使用变量的值来自动推导出变量的类型。但在某些时候,比如在第2章的“比较猜测数字与保密数字”一节中,当我们需要使用parse将一个String类型转换为数值类型时,就必须显式地添加一个类型标注

标量类型

整数 浮点数 布尔值 字符

  • 整数
    | 长度 | 有符号 | 无符号 | | — | — | — | | 8-bit | i8 | u8 | | 16-bit | i16 | u16 | | 32-bit | i32 | u32 | | 64-bit | i64 | u64 | | arch | isize | usize |
  • 浮点数
    Rust 的浮点数类型是 f32 和 f64,分别占 32 位和 64 位。默认浮点类型是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。
  • 布尔值
    Rust 中的布尔类型有两个可能的值:true 和 false。Rust 中的布尔类型使用 bool 表示。例如:let t = true; let f: bool = false;
  • 字符
    字符类型使用 char 类型表示,使用单引号指定。例如:let c = 'z';Rust中的char类型占4字节,是一个Unicode标量值,这也意味着它可以表示比ASCII多得多的字符内容

复合类型

元组 数组
元组可以存储不同类型的值,但是数组只能存储相同类型的值。

  • 元组(tuple)
fn main() { 
 let tup = (500, 6.4, 1); 
 // let tup: (i32, f64, u8) = (500, 6.4, 1);
 let (x, y, z) = tup; // 解构
 println!("The value of y is: {}", y); 
 let five_hundred = tup.0; // 使用 . 来访问元组的元素
}
  • 数组
fn main() {
    let a = [1, 2, 3, 4, 5];
    // let a: [i32; 5] = [1, 2, 3, 4, 5];
    let b = [3,5] // 等同于 let b = [3, 3, 3, 3, 3];
    let first = a[0];
}

函数

fn main() { 
    println!("Hello, world!"); 
    another_function(); 
} 
fn another_function(x: i32) { 
    println!("The value of x is {}",x); 
} 

注意:关键字fn,程序开始main函数,蛇形命名法
要显式声明函数参数类型

函数中的语句和表达式

语句指那些执行操作但不返回值的指令,而表达式则是指会进行计算并产生一个值作为结果的指令。

fn main() { 
    let x = 5; 
    let y = {
        let x = 3; 
        x + 1 //注意这里没有分号,表示一个表达式。分号表示语句结束
    }; 
    println!("The value of y is: {}", y); 
} 

调用函数是表达式,调用宏是表达式,我们用来创建新作用域的花括号({})同样也是表达式

函数的返回值

在Rust中,函数的返回值等同于函数体最后一个表达式的值。

fn main() { 
    let x = plus_one(5); 
    println!("The value of x is: {}", x); 
} 
fn plus_one(x: i32) -> i32 { 
    x + 1 //有分号会报错
} 

控制流

条件

错误

fn main() { 
    let number = 3; 
    if number { 
        println!("number was three"); 
    } 
} 

Rust不会自动尝试将非布尔类型的值转换为布尔类型。你必须显式地在if表达式中提供一个布尔类型作为条件

在let语句中使用if

fn main() { 
    let condition = true; 
    let number = if condition { 
        5 
    } else { 
        6 
    }; 
    println!("The value of number is: {}", number); 
} 

注意:if和else后面的代码块必须返回相同的类型

循环

Rust 有三种循环:loop、while 和 for

  • loop
    loop关键字指示Rust反复执行某一块代码,直到我们显式地声明退出为止。
fn main() { 
 loop { 
 println!("again!"); 
 } 
} 

从loop循环中返回值 我们可以将需要返回的值添加到break表达式后面

fn main() { 
    let mut counter = 0; 
    let result = loop { 
        counter += 1; 
        if counter == 10 { 
            break counter * 2; 
        } 
    }; 
    println!("The result is {}", result); 
} 
  • while\for
fn main() { 
    let a = [10, 20, 30, 40, 50]; 
    for element in a.iter() { 
        println!("the value is: {}", element); 
    } 
} 
fn main() { 
    for number in (1..4).rev() { 
        println!("{}!", number); 
    } 
    println!("LIFTOFF!!!"); 
}

第4章 认识所有权

什么是所有权

一般来讲,所有的程序都需要管理自己在运行时使用的计算机内存空间。某些使用垃圾回收机制的语言会在运行时定期检查并回收那些没有被继续使用的内存;而在另外一些语言中,程序员需要手动地分配和释放内存。Rust采用了与众不同的第三种方式:它使用包含特定规则的所有权系统来管理内存,这套规则允许编译器在编译过程中执行检查工作,而不会产生任何的运行时开销。

请自行研究

所有权规则

  1. Rust中的每一个值都有一个对应的变量作为它的所有者。
  2. 在同一时间内,值有且仅有一个所有者。
  3. 当所有者离开自己的作用域时,它持有的值就会被释放掉。

个人理解:栈区的指针释放时,自动释放它指向的堆区的内容