The Rust Programming Language

Rust 编程语言笔记。

起源:The Rust Programming Language Book 。


装置

应用 rustup 来装置 Rust

Rust 源文件以 .rs 作为扩展名。

几个罕用的命令:

  • 编译:rustc .rs-file
  • 运行:./compiled-file
  • 查看 Rust 编译器版本:rustc --version
  • 查看 rustup 版本:rustup --version
  • 更新 Rust 编译器:rustup update
  • 卸载 Rustrustuprustup self uninstall
  • 本地文档:rustup doc

包管理工具

Rust 的包管理工具是 Cargo

几个罕用的命令:

  • 查看 cargo 的版本:cargo --version
  • 新建我的项目:cargo new
  • 我的项目构建:cargo build
  • 运行我的项目:cargo run
  • 我的项目查看:cargo check:该命令确保我的项目能够编译,但不生成可执行文件,速度比 cargo build 更快

Rust 应用 TOML(Tom's Obvious Minimal Language) 格局来治理依赖。

应用 cargo new 创立新我的项目后,在该项目标目录下会有名为 Cargo.toml 的文件来治理依赖和包。

能够应用 cargo add 来增加依赖,也能够在 .toml 文件的 [dependencies] 字段下增加包名。

例如:

[dependencies]rand = "0.8.5"

包的版本应用三位的规范包规范

.rs 文件中应用关键字 use 来导入包。

标准

  • Rust 的缩进采纳的是 4 个 space,而不是 tab
  • Rust 应用 snake case 对变量和函数命名,也就是全副应用小写字母,单词两头应用下划线 _ 连贯,例如:var_name

Hello World

fn main() {    println!("Hello, World!");}
  • fn 是函数(function)的关键词
  • main() 是 Rust 的主函数、相似于 C、C++
  • 每行完结须要用分号 ; 示意

正文

Rust 有三种正文:

  • 单行正文: //
  • 多行正文:/* */
  • 文档(DocString)正文:/** */

变量

Rust动态类型语言,在申明变量时须要应用关键词 let 并在冒号 : 后指明变量的类型。这点相似于 Python 的 Type-Hint 以及 TypeScript

let var: u8 = 0;

可修改性

Rust 中的所有变量都有可批改(mutable)或不可修改性(immutable),如果在申明变量时不明确指明,那么默认为不可批改。

应用关键字 mut 示意变量能够批改。

let mut var: u8 = 2;u8 = 3; // That's OKlet ano_var: u8 = 2;u8 = 3; // Error

shadowing

fn main() {    let x: u32 = 5;      let x = x + 1;      {        let x = x * 2;        println!("The inner x: {x}");      }      println!("The outer x: {x}");}// The inner x: 12// The outer x: 6

如上述代码所示:申明了多个名为 x 的变量,在 Rust 中,咱们称 第一个 x 被第二个 x shadow,或者 第二个 x overshadow 了第一个 x,这意味着:当应用 x 这个变量时,编译器总是应用第二个 x,即第二个 x 拿走了第一个 x 的所有,直到程序流来到第二个 x 的作用域或者第二个 x 也被 shadow。

shadow 和 mut 的区别

  1. shadow 使得能够扭转同名变量的类型,然而 mut 会在编译时出错

    fn main() {    let x: &str = "     ";      let x: usize = x.len(); // 5      let mut x: &str = "     ";    x = x.len()             // Error}
  2. shadow 使得能够批改不可批改的同名变量的值

    fn main() {    let x: u32 = 5;    x = 6;             // Error, 因为没有变量默认是不可批改的        let x: u32 = 5;    let x = 6;      println!("{}", x)  // 6}

常量

Rust 应用 const 关键字申明常量。通常来说,须要用大写字母申明常量。

const THE_DAY_I_START_LEARNING_RUST: String = "2023.5.9";

不可批改的变量和常量的区别在于:

  1. 常量只能是不可批改的,不能通过 mut 关键字使得常亮能够批改
  2. 常量通常只赋值给常量申明的表达式,而不是运行时的计算表达式
  3. 常量能够在任何作用域(scope) 中申明,在程序运行期间,在其申明的作用域中是无效的

数据类型

Rust 是动态类型语言,因而在编译时就须要晓得所有的变量类型。

例如在数据转换中:

fn main() {    let var = "100".parse().expect("Not a number!"); // Error    let var: u32 = "100".parse().expect("Not a number"); // OK, var == 100}

根本类型

Rust 的根本数据类型有 4 种:

  • 布尔 bool
  • 整型 integer
  • 浮点型 float
  • 字符型 char

布尔型

布尔型有两个值:

  1. true
  2. false

整型

整型有 6 种长度,每种长度分类有符号无符号两类。

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

整型字面量(literal)

字面量举例
十进制98_222
十六进制0xff
八进制0o77
二进制0b1111_0000
字节(u8)b'A'
  • 整型的默认类型为 i32
  • 在应用汇合类数据类型的索引时,应用 usizeisize

浮点型

浮点型有两类,而且都是有符号的:

  • f32
  • f64:默认类型

字符型

字符型用 c (character)标识。

复合类型

Rust 的复合类型包含:

  • 元组
  • 数组

元组

元组 tuple:用括号 () 申明,元组元素的数据类型能够不同

元组是定长的,一旦申明后就不能扭转大小。

let tup: (u32, f32, bool) = (1, 2.2, true);

Python 不同,Rust 中的元组能够应用 . 运算符来拜访。

let tup: (u32, f32, bool) = (1, 2.2, true);println!("{}", tup.0); // 1println!("{}", tup.2); // 2.2println!("{}", tup.3); // true

数组

数组 array: 用方括号 [] 申明,数组元素的数据类型必须雷同

数组也是定长的。

let arr: [u8; 5] = [1, 2, 3, 4, 5];

; 的前后别离示意数组元素的类型和数组元素的个数。

能够应用索引 [],拜访数组元素,因为数组以定长模式存储在栈中:

let first = arr[0];

管制

条件

if, else if, else 等关键字控制程序流。

Rust 的条件语句不须要外嵌圆括号 (),然而也不同于 Python 的 :,条件执行体须要用花括号:{}

fn main() {  let var: u32 = 8;  if var > 0 {    println!("{var} is greater than 0!");  } else if var < 0 {    println!("{var} is less than 0!");  } else {    println!("{var} is equal to 0!");  }}

注:和 JavaScriptRuby 等语言不同,Rust 语言不会在条件判断时主动转换变量的类型,例如:

fn main() {    let var: bool = true;  if var == 0 {    println!("You can't get there in Rust");  }}

循环

Rust 中有 3 种循环:

  • 有限循环 loop
  • while 循环
  • for 循环

完结、跳出循环的关键字:

  • break 跳出以后循环
  • continue 完结本次循环(开始下一次循环)

loop 循环

Rust 能够应用关键字 loop 来创立有限循环,例如:

loop {  println!("This is a infinite loop");}// 等价于while true {  println!("This is a infinite loop");}

continueloop 循环有效。

能够用 `nameloop 循环命名(标识符)以跳出多层循环,例如:

fn main() {  let mut count: u32 = 10;    `outer: loop {    let mut remaining: u32 = 2;    loop {      println!("{}", count * remaining);      remaining -= 1;      if remaining == 0 {        break outer;      }    }    count -= 1;    println!("{}", count);    if count == 0 {      break;    }  }}

while 循环

相似于其余语言的 while 循环。

同样,Rust 的循环条件语句不须要外嵌圆括号 (),然而也不同于 Python 的 :,循环体须要用花括号:{}

fn main() {  let mut count = 10;  while count > 0 {    println!("{}", count);    count -= 1;  }}

for 循环

for in

for in 循环对遍历对象中的每一个元素都执行遍历:

fn main() {  let arr: [u32; 5] = [1, 2, 3, 4, 5];  for element in arr {    println!("{}", element);  }}
for range

for range 相似于 Python 的同名函数。

fn main() {  for i in 0..5 {    println!("{}", i);  }}

应用 .rev() 倒序输入:

fn main() {  for i in (0..5).rev() {    println!("{}", i);  }}

函数

应用关键字 fn 申明函数,Rust 总是首先执行 main 函数。

fn main() {  let var: u32 = 3;  increment_and_print(var);}fn increment_print(num: u32) -> u32 {    num += 1;  println!("{}", num);  return num;  // num}

函数的参数须要申明名称和类型,返回值用 -> 示意,只须要申明类型。

能够应用关键字 return 显式返回值,也能够把返回值写在最初一行(不要应用 ; 结尾)。Rust 默认把最初一行的值作为返回值。

输出和输入

输出

应用规范库 std::io 来导入规范库的 io。

use std::io;fn main() {  let mut inp: String = String::new();     io::stdin.read_line(&mut inp).expect("Failed to read");   println!("{inp}");}
  • 应用 stdin 引入规范输出流,
  • 应用 read_line(&) 来读取输出,
  • 应用 expect() 来解决异常情况。

输入

应用 println!() 来输入内容。

println!() 示意调用 macroprintln() 示意调用函数

Rust 不反对间接输入变量的值,必须格式化(format)后输入。在引号 "" 中使花括号 {} 来输入变量。

fn main() {    let var: u32 = 15;      println!("{}", var); // 15      // println!("var equals {var}")  Also ok!      // println!(var)  Error!}

构造体

Rust 的构造体相似于 C,应用关键字 struct 申明。

构造体中的每个元素称为“域”(field),域是可批改的(mutable),应用 . 来拜访域的值。

struct User {  active: bool,  sign_in_count: u32,  username: String,  email: String}fn main() {  let user = User {    active: false,    sign_in_count: 1,    username: String::from("someusername"),    email: String::from("someuseremail"),  };    user1.email = "anotheremail";}

能够应用 .. 来简化域成员的赋值:

struct User {  active: bool,  sign_in_count: u32,  username: String,  email: String}fn main() {  let user = User {    active: false,    sign_in_count: 1,    username: String::from("someusername"),    email: String::from("someuseremail"),  };    let user_2 = User {    active: true,    ..user1  }}

下面的代码示意,除了域 active 之外,user_2 的其余域值和 user 相等。

注:..user 后没有 ,

枚举

例如上面的代码:

use std::cmp::Ordering;use std:io;fn main() {        println!("This is a guessing game");      const SECRET_NUMBER: u32 = 12;      let mut guess: String = String::new();      println!("Enter your guess: ");      io::stdin.read_line(&mut guess).expect("Failed to read line");      let mut guess = match guess.parse().wrap() {      Ok(num) => num,      Err(_) => {        println!("You should enter a number!");      }      }      match guess.cmp::Ordering {          Less => println!("Too small!"),      Greater => println!("Too big!"),      Equal => println!("You are the winner!");  }}

match 关键字用于开始匹配枚举。

这段代码中用到了两个枚举类型,别离是:

  1. guess 的类型判断会返回枚举类型 Result,它有 OkErr 两个枚举值,别离示意胜利和谬误两种状况
  2. guessSECRET_NUMBER 两个值之间的比拟会返回枚举类型 Ordering,它有 LessGreaterEqual 三种状况,别离示意小于,大于和等于。

待续