《Rust 程序设计语言》 简体中文版
《The Rust Programming Language》英文版
熟悉关于Rust单词:
Rustacean:Rust编程语言的用户或开发者。
Rust 介绍 什么选择 Rust?
高性能
Rust 速度惊人且内存 利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备 上运行,还能轻松和其他语言集成。
可靠性
Rust 丰富的类型系统和所有权模型保证了内存安全 和线程安全 ,让您在编译期就能够消除各种各样的错误。
生产力
Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息, 还集成了一流的工具——包管理器和构建工具, 智能地自动补全和类型检验的多编辑器支持, 以及自动格式化代码等等。
Rust 的历史?
Rust语言原本是 Mozilla 员工 Graydon Hoare
的个人项目,而 Mozilla 于2009年开始赞助这个项目,并且在2010年首次公开。也在同一年,其编译器源代码开始由原本的OCaml语言 转移到用Rust语言,进行自我编译工作,称做“rustc”,并于2011年实际完成。这个可自我编译的编译器在架构上采用了LLVM 做为它的后端。
第一个有版本号的Rust编译器于2012年1月发布。Rust 1.0是第一个稳定版本,于2015年5月15日发布 。
Rust 开发工具
Cargo 是Rust 官方构建系统和包管理器,它能轻松增加、编译和管理依赖,并使依赖在 Rust 生态系统中保持一致。Rust 的编译工具依赖 C 语言的编译工具,这意味着你的电脑上至少已经存在一个 C 语言的编译环境。如果你使用的是 Linux 系统,往往已经具备了 GCC 或 clang。
项目管理:Cargo 用于创建、构建、管理 Rust项目。通过 Cargo,你可以轻松地创建新项目,管理项目的依赖关系,并执行项目的构建、运行和测试等操作。
包管理器:Cargo 还充当了 Rust 的包管理器。它允许开发者在项目中引入和管理依赖项(如第三方库),并确保这些依赖项的版本管理和兼容性。
Rustfmt 格式化工具确保开发者遵循一致的代码风格。
rust-analyzer 为集成开发环境(IDE)提供了强大的代码补全和内联错误信息功能
Cargo 常用命令:
cargo new <project-name>
:创建一个新的 Rust 项目。
cargo build
:编译当前项目。
cargo run
:编译并运行当前项目。
cargo check
:检查当前项目的语法和类型错误。
cargo test
:运行当前项目的单元测试。
cargo update
:更新 Cargo.toml 中指定的依赖项到最新版本。
cargo --help
:查看 Cargo 的帮助信息。
cargo publish
:将 Rust 项目发布到 crates.io。
cargo clean
:清理构建过程中生成的临时文件和目录。
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 33 34 35 36 37 38 39 40 41 42 pi@pi-NMH-WCX9:~/Rust$ cargo --help Rust's package manager Usage: cargo [+toolchain] [OPTIONS] [COMMAND] cargo [+toolchain] [OPTIONS] -Zscript <MANIFEST_RS> [ARGS]... Options: -V, --version Print version info and exit --list List installed commands --explain <CODE> Provide a detailed explanation of a rustc error message -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never -C <DIRECTORY> Change to DIRECTORY before doing anything (nightly-only) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see ' cargo -Z help ' for details -h, --help Print help Commands: build, b Compile the current package check, c Analyze the current package and report errors, but don' t build object files clean Remove the target directory doc, d Build this package's and its dependencies' documentation new Create a new cargo package init Create a new cargo package in an existing directory add Add dependencies to a manifest file remove Remove dependencies from a manifest file run, r Run a binary or example of the local package test , t Run the tests bench Run the benchmarks update Update dependencies listed in Cargo.lock search Search registry for crates publish Package and upload this package to the registry install Install a Rust binary uninstall Uninstall a Rust binary ... See all commands with --list See 'cargo help <command>' for more information on a specific command .
Rust 应用场景
命令行工具
Web服务
DevOps工具
嵌入式设备
音视频分析与转码
加密货币
生物信息学
搜索引擎
物联网(IOT)程序
机器学习
Rust 安装 通过 rustup
安装官方的编译器 rustc
和 构建系统工具&包管理工具 cargo
。
在 Linux 或 macOS 的命令行终端执行:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 alex@alex-NMH-WCX9:~$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh info: downloading installer Welcome to Rust! This will download and install the official compiler for the Rust programming language, and its package manager, Cargo. Rustup metadata and toolchains will be installed into the Rustup home directory, located at: /home/alex/.rustup This can be modified with the RUSTUP_HOME environment variable. The Cargo home directory is located at: /home/alex/.cargo This can be modified with the CARGO_HOME environment variable. The cargo, rustc, rustup and other commands will be added to Cargo's bin directory, located at: /home/alex/.cargo/bin This path will then be added to your PATH environment variable by modifying the profile files located at: /home/alex/.profile /home/alex/.bashrc You can uninstall at any time with rustup self uninstall and these changes will be reverted. Current installation options: default host triple: x86_64-unknown-linux-gnu default toolchain: stable (default) profile: default modify PATH variable: yes 1) Proceed with standard installation (default - just press enter) 2) Customize installation 3) Cancel installation > info: profile set to 'default' info: default host triple is x86_64-unknown-linux-gnu info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu' info: latest update on 2024-11-28, rust version 1.83.0 (90b35a623 2024-11-26) info: downloading component 'cargo' 8.6 MiB / 8.6 MiB (100 %) 140.8 KiB/s in 58s ETA: 0s info: downloading component 'clippy' 2.7 MiB / 2.7 MiB (100 %) 155.8 KiB/s in 17s ETA: 0s info: downloading component 'rust-docs' 16.4 MiB / 16.4 MiB (100 %) 244.4 KiB/s in 1m 44s ETA: 0s info: downloading component 'rust-std' 26.1 MiB / 26.1 MiB (100 %) 146.2 KiB/s in 4m 0s ETA: 0s info: downloading component 'rustc' 69.3 MiB / 69.3 MiB (100 %) 134.4 KiB/s in 11m 10s ETA: 0s info: downloading component 'rustfmt' 2.4 MiB / 2.4 MiB (100 %) 150.4 KiB/s in 22s ETA: 0s info: installing component 'cargo' info: installing component 'clippy' info: installing component 'rust-docs' 16.4 MiB / 16.4 MiB (100 %) 10.9 MiB/s in 1s ETA: 0s info: installing component 'rust-std' 26.1 MiB / 26.1 MiB (100 %) 16.5 MiB/s in 1s ETA: 0s info: installing component 'rustc' 69.3 MiB / 69.3 MiB (100 %) 17.9 MiB/s in 3s ETA: 0s info: installing component 'rustfmt' info: default toolchain set to 'stable-x86_64-unknown-linux-gnu' stable-x86_64-unknown-linux-gnu installed - rustc 1.83.0 (90b35a623 2024-11-26) Rust is installed now. Great! To get started you may need to restart your current shell. This would reload your PATH environment variable to include Cargo's bin directory ($HOME/.cargo/bin). To configure your current shell, you need to source the corresponding env file under $HOME/.cargo. This is usually done by running one of the following (note the leading DOT): . "$HOME/.cargo/env" # For sh/bash/zsh/ash/dash/pdksh source "$HOME/.cargo/env.fish" # For fish
安装完成,重启当前的 Terminal ,检查 rustc 版本,执行命令:
1 2 $ rustc --version rustc 1.83.0 (90b35a623 2024-11-26)
接着检查 cargo 版本,执行命令:
1 2 $ cargo --verison cargo 1.83.0 (5ffbef321 2024-10-29)
VSCode Rust插件
rust-analyzer :实时编译和分析 Rust 代码,提示代码中的错误,还可以代码跳转,并对类型进行标准。
Even Better TOML :支持 .toml 文件语法高亮
CodeLLDB :调试器
Error Lens:支持获得错误提示
CodeLLDB:支持 Debugger 程序
Rust Syntax:支持 Rust 语法高亮
Git Graph :支持 Git 以图形化显示,还是可以进行通过UI执行 git 命令
在 VSCode 中对 Rust 进行 Debug 调试,在当前项目的同一级目录创建 .vscode
文件夹,该文件夹下有 launch.json
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "version" : "0.2.0" , "configurations" : [ { "type" : "lldb" , "request" : "launch" , "name" : "Debug" , "program" : "${workspaceFolder}/target/debug/${workspaceFolderBasename}" , "args" : [ ] , "cwd" : "${workspaceFolder}" } ] }
VSCode 定义了很多变量(Variables Reference ),用户可以直接使用:
Predefined variables
The following predefined variables are supported:
${userHome} - the path of the user’s home folder
${workspaceFolder} - the path of the folder opened in VS Code
${workspaceFolderBasename} - the name of the folder opened in VS Code without any slashes (/)
${file} - the current opened file
${fileWorkspaceFolder} - the current opened file’s workspace folder
${relativeFile} - the current opened file relative to workspaceFolder
${relativeFileDirname} - the current opened file’s dirname relative to workspaceFolder
${fileBasename} - the current opened file’s basename
${fileBasenameNoExtension} - the current opened file’s basename with no file extension
${fileExtname} - the current opened file’s extension
${fileDirname} - the current opened file’s folder path
${fileDirnameBasename} - the current opened file’s folder name
${cwd} - the task runner’s current working directory upon the startup of VS Code
${lineNumber} - the current selected line number in the active file
${selectedText} - the current selected text in the active file
${execPath} - the path to the running VS Code executable
${defaultBuildTask} - the name of the default build task
${pathSeparator} - the character used by the operating system to separate components in file paths
${/} - shorthand for ${pathSeparator}
Rust 语法 但凡编程语言,基本都会有一个共性:数据、数据类型、关键字、分支结构、循环结构、函数。
数据 变量和常量 变量默认是不可改变的(immutable)。
常量(constants)是绑定到一个名称的、不允许改变的值,不过常量与变量还是有一些区别。
声明常量使用 const
关键字,不允许对常量使用 mut
,并且 必须 注明值的类型。
常量不光默认不可变,它总是不可变。
常量 只能 被设置为常量表达式,而不可以是其他任何 只能 在运行时计算出的值。
声明一个常量的例子:
1 const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3 ;
Rust 对常量的命名约定是在单词之间使用全大写加下划线(非强制性要求)。
Rust 是强类型语言,但具有自动判断变量类型的能力。
默认情况下,Rust 中的变量是不可变的,除非使用 mut 关键字声明为可变变量。
1 2 let a = 123 ; let mut b = 10 ;
隐藏 可以定义一个与之前变量同名的新变量,第一个变量被第二个变量 隐藏(Shadowing) 了,不仅隐藏了变量名称,而且还隐藏了变量类型。这在C语言中是不被允许的,而且编译会报错:重复定义变量。
1 2 3 4 5 6 7 8 9 fn main () { let x = 5 ; let x = x + 1 ; { let x = x * 2 ; println! ("the value of x in the inner scope is: {x}" ); } println! ("the value of x is: {x}" ); }
基本数据类型 Rust 是静态类型语言,也就是说:在编译时就必须知道所有变量的类型。根据值及其使用方式,编译器通常可以推断出我们想要的类型,尽管我们没有显示说明具体类型。
Rust 有两类数据类型子集:标量(scalar)和 复合(compound)。
标量类型代表一个单独的值。Rust 有 4 种基本的标量类型:整型、浮点型、布尔类型、字符类型 。
标量类型 Rust 中的整型 :
长度
有符号
无符号
8 bit
i8
u8
16 bit
i16
u16
32 bit
i32
u32
64 bit
i64
u64
128 bit
i128
u128
arch
isize
usize
注意:isize 和 usize 类型依赖运行程序的计算机架构:32位架构上他们是32位的,64为架构上他们是64位的。
Rust 整型字面值:
数字字面值
例子
Decimal(十进制)
98_222
Hex(十六进制)
0xff
Octal(八进制)
0o77
Binary(二进制)
0b1111_0000
Byte(单字节字符,仅限于u8)
b’A’
如果没有显示定义数字类型,Rust 的默认整型类型通常是 i32 。
Rust 的浮点数类型 是 f32 和 f64,默认浮点数类型是 f64 ,所有浮点数类型都是有符号的 。
1 2 3 4 fn main () { let x = 2.0 ; let y : f32 = 3.0 ; }
注意:let
是关键字
Rust 的布尔类型 :true 和 false。
1 2 3 4 5 fn main () { let t = true ; let f : bool = false ; }
Rust 的字符类型 :char,char 类型的大小为 四字节 ,并代表了一个 Unicode 标量值,这意味着它可以比 ASCII 表示更多内容。在 Rust 中,带变音符号的字母,中文、日文、韩文等字符,emoji (绘文字)以及零长度的空表字符都是有效的 char 值。
注意:这里一定把C语言中的char 类型区分开来,C语言中char 类型只有1个字节。
1 2 3 4 5 fn main { let c = 'z' ; let z : char = 'Z' ; let heart_eyed_cat = '😻'; }
复合类型 复合类型可以将多个值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和 数组(array)。
元组是一个将多个其他数据类型的值组合到一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增加或减小。
1 2 3 4 5 6 7 8 9 10 11 12 13 fn main () { let tup : (i32 , f64 , u8 ) = (500 , 6.4 , 1 ); let (x, y, z) = tup; println! ("x is: {x}, y is: {y}, z is: {z}" ); let one = tup.0 ; let two = tup.1 ; let three = tup.2 ; println! ("one is: {one}, two is: {two}, three is: {three}" ); }
数组是将多个相同数据类型组合到一起。Rust 中的数组长度是固定的。
1 2 3 4 5 6 7 8 fn main () { let a = [1 ,2 3 , 4 ,5 ]; let months = ["January" , "February" , "March" , "April" , "May" , "June" , "July" , "August" , "September" , "October" , "November" , "December" ]; let b : [i32 ; 5 ] = [1 , 2 , 3 , 4 , 5 ]; let c = [3 ; 5 ]; }
注意:通过索引访问数组中的元素,索引从0开始
函数 Rust 使用 fn
关键字声明函数。Rust 代码中的函数和变量名使用 snake case 规范风格。在 snake case 中,所有字母都是 小写 并使用 下划线 分隔单词。
在函数签名中, 必须 声明每个参数的类型:要求在函数定义中提供乐行注解,意味着编译器再也不需要你在代码的其他地方注明类型来支出你的意图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fn main () { let x : i32 = 10 ; let y : i32 = 15 ; let z : i32 = sum (x, y); println! ("{x} + {y} == {z}" ); } fn sum (x: i32 , y: i32 ) -> i32 { return x + y; } fn print_hello (){ println! ("hello world" ); }
注意:
1、在C语言中,sum函数的调用出现在定义之前是不被允许的,编译时会报错。但是在Rust 中,这种做法是没有问题的。
2、Rust 不支持自动返回值类型判断!如果没有明确声明函数返回值的类型,函数将被认为是”纯过程”,不允许产生返回值,return 后面不能有返回值表达式。
控制流 控制流一般是通过 分支结构 和 循环结构 实现。
if else 分支结构
Rust 代码中最常见的用来控制执行流的关键字是:if
、else
、else if
1 2 3 4 5 6 7 8 9 10 11 12 13 fn main () { let number = 6 ; if number % 4 == 0 { println! ("number is divisible by 4" ); } else if number % 3 == 0 { println! ("number is divisible by 3" ); } else if number % 2 == 0 { println! ("number is divisible by 2" ); } else { println! ("number is not divisible by 4, 3, or 2" ); } }
注意:
1、number % 4 ==0
可以不用 ()
包裹, 当然也可以加上。
2、分支语句块必须使用 {}
包裹,尽管语句块只有一条语句也需要使用 {}
。
另外,Rust 中条件表达式的值必须是布尔类型(即 bool),不能通过一个整数的值来作为判断条件(即 0为真,非0为假)
1 2 3 4 5 6 fn main () { let number = 3 ; if number { println! ("Yes" ); } }
循环结构
Rust 提供了多种循环:loop
、while
、for
。
loop 1 2 3 4 5 fn main () { loop { println! ("again!" ); } }
可以使用关键字 break
跳出循环体,使用关键字 continue
跳过这一轮循环,进入下一轮循环。
从循环返回值 ,即结束循环,然后返回一个值
1 2 3 4 5 6 7 8 9 10 11 12 13 fn main () { let mut counter = 0 ; let result = loop { counter += 1 ; if counter == 10 { break counter * 2 ; } }; println! ("The result is {result}" ); }
循环标签 :在多个循环之间消除歧义
这个功能有点像C语言中的 goto
跳转到指定标签功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn main () { let mut count = 0 ; 'counting_up : loop { println! ("count = {count}" ); let mut remaining = 10 ; loop { println! ("remaining = {remaining}" ); if remaining == 9 { break ; } if count == 2 { break 'counting_up ; } remaining -= 1 ; } count += 1 ; } println! ("End count = {count}" ); }
while while 循环
1 2 3 4 5 6 7 8 9 10 11 fn main () { let mut number = 3 ; while number != 0 { println! ("{number}!" ); number -= 1 ; } println! ("LIFTOFF!!!" ); }
注意:do while() 循环的用法目前还不支持。
for for 循环
使用 for 循环遍历数组
1 2 3 4 5 6 7 fn main () { let a = [10 , 20 , 30 , 40 , 50 ]; for element in a { println! ("the value is: {element}" ); } }
使用 for 循环遍历元组
1 2 3 4 5 6 fn main () { for number in (1 ..4 ).rev () { println! ("{number}!" ); } println! ("LIFTOFF!!!" ); }
迭代器 所有权 所有权 (ownership )是 Rust 用于如何管理内存的一组规则。所有程序都必须管理其运行时使用计算机内存的方式。
Rust 则选择的方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。
所有权规则:
Rust 中的每一个值都有一个 所有者 (owner )。
值在任一时刻有且只有 一个所有者。
当所有者(变量)离开作用域,这个值将被丢弃。
结构体 Rust 定义结构体,需要使用关键字 struct
并为整个结构体提供一个名字。
定义一个用户结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct User { active: bool , username: String , email: String , sign_in_count: u64 , } fn main () { let user1 = User { active: true , username: String ::from ("someusername123" ), email: String ::from ("someone@example.com" ), sign_in_count: 1 , }; println! ("User Info: username: {} email: {} active: {} sign_in_count: {}" , user1.username, user1.email, user1.active, user1.sign_in_count); }
定义一个长方形结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct Rectangle { width: u32 , height: u32 , } fn main () { let rect1 = Rectangle { width: 30 , height: 50 , }; println! ( "The area of the rectangle is {} square pixels." , area (&rect1) ); } fn area (rectangle: &Rectangle) -> u32 { rectangle.width * rectangle.height }
枚举类型 方法 方法 (method)与函数类似:它们使用 fn
关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并且它们第一个参数总是 self
,它代表调用该方法的结构体实例。
编译管理