Skip to content

学习 Rust 的一些笔记

· 9 min
TL;DR

Rust 是一门偏底层的,安全的,高效的开源编程语言。

本文记录了作者学习 Rust 语言的笔记和心得,涵盖从工具链到语言特性的核心内容。首先介绍了 rustup、cargo 等基础工具的安装和使用方法;然后详细讲解了 Rust 的变量特性、数据类型和内存管理模型,包括不可变变量、栈与堆的区别、所有权系统等独特概念;最后总结了 Rust 借鉴其他语言的优点以及自身的创新特性。这篇文章为 Rust 初学者提供了简明扼要的入门指南和关键知识点概览。

工具链#

rustup 是管理 Rust 版本和相关工具的命令行工具 (rust toolchain installer)

Rust 工具链中包括 rustc 编译器工具,rustfmt 格式化工具,rustdoc 文档化工具等。

rustc 类似于 C/C++ 中的 gcc/clang

CargoRust 的构建系统和包管理器。可以进行构建代码、下载依赖库并编译这些库等。

cargo new rust-proj 创建一个 Rust 项目,

Terminal window
$ cargo new rust-proj
Created binary (application) `rust-proj` package
$ tree rust-proj
rust-proj
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files

Cargo 会在 hello_cargo 目录初始化一个 git 仓库,以及一个 .gitignore 文件。如果你在现有的 git 仓库中运行 cargo new,则不会生成 git 文件;你可以通过使用 cargo new --vcs=git 来覆盖此行为。

可以通过 --vcs 参数使 cargo new 切换到其它版本控制系统(VCS),或者不使用 VCS。运行 cargo new --help 参看可用的选项。

cargo build 构建项目,目标可执行文件在 target/debug/

cargo run 则是构建项目并运行。

cargo check 检查项目代码正确,确保可编译。不会产生可执行文件。

cargo build 默认构建是 debug 模式。如果项目一切都 OK,可以运行 cargo build --release 执行发布构建,这会对项目进行一定编译优化,从而使得代码运行得更快,但是相应地,编译时间会更长。

cargo doc --open 会生成当前项目中的依赖库 (crate) 的文档,并转到浏览器可以查询。

Hello, World!#

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

cargo new 生成的项目中,包含配置文件 Cargo.toml

文件名:Cargo.toml

[dependencies]
rand = "0.8.3"

其中”0.8.3”指定依赖版本,其语法遵循语义化版本 (Semantic Versioning)

这里的 0.8.3 实际上是 ^0.8.3 的简写,它表示 任何不低于 0.8.3,但是低于 0.9.0 的版本。Cargo 将这些版本视作与 0.8.3 版本公有 API 相兼容的版本,这个声明确保你将获得最新的补丁版本,它仍然可以与本章中的代码正常编译。0.9.0 或以上版本不保证拥有接下来示例中使用到的 API。


一些定义#

语句 (statement) 和表达式 (expression)

Rust 是一门基于表达式的语言。

语句是执行一些操作,但是不返回值的指令。

函数定义 就是一个语句。

表达式计算并产生一个值,可以赋予其它变量。

函数调用 是一个表达式,大括号创建的块作用域也是一个表达式。

表达式的结尾没有分号,如果结尾加上分号,则变成了语句。

数字本身就是一个表达式,所以它可以返回本身的值赋值给其它变量。

栈 (stack) 中的数据必须占用已知且大小固定的大小。

当数据大小未知,或大小可能变化的时候,需要用堆 (heap)。比如使用内存分配器 memory allocator 分配指定大小的内存,此时该块内存会被标记为已用,并且以指针来表示这块内存。

而将数据放入栈中的过程并不叫做分配内存,因为这个过程并没有新的内存被分配。

堆的指针可以存储在栈上。

入栈比在堆上分配内存要快。

访问堆中的数据比访问栈上的数据要慢,因为访问堆首先要通过指针来访问,而指针在栈上。


一些笔记#


enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
enum Option<T> {
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("a string");
# 当为 `None` 时,必须显示指定类型 `<T>`
let absent_number: Option<i32> = None;

关于字符串方法,以下两种方法等效:

let s1 = String::from("initial contents");
let s2 = "initial contents".to_string();

参考链接: