【rust编程】rust的极速入门
开篇先言
Rust 是一门现代系统编程语言,专注于性能、内存安全和并发性。它可能比 Python 或 JavaScript 等语言有更陡峭的学习曲线,但这道门槛背后是巨大的回报。Rust 通过其创新的编译器和所有权系统,能够在编译时就消除整类的常见编程错误(如空指针解引用、数据竞争等),这使得开发者可以编写出既快速又极其可靠的软件。学习 Rust 不仅是学习一门新语言,更是学习一种构建高质量软件的思维方式。所以,加油学习吧!成长的道路依然长远。
1. 环境搭建与第一个程序
开启任何编程旅程的第一步都是配置好开发环境。Rust 提供了一个名为 rustup 的官方工具链管理器,极大地简化了安装和管理过程。
1.1 安装 Rust
Rust 的安装过程非常标准化。在Windows 环境下可以直接通过官网(https://rust-lang.org/zh-CN/learn/get-started/)去下载,或是在类 Unix 系统(如 Linux, macOS)或 Windows 的 WSL 的环境中,我们还可以通过在终端执行以下命令来安装 rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup 会负责安装 Rust 编译器 rustc、标准库,以及至关重要的包管理器和构建工具 Cargo 。安装完成后,我们可以打开一个新的终端窗口,通过以下命令验证安装是否成功:
rustc --version
cargo --version
如果能看到版本号输出,说明我们的 Rust 开发环境已准备就绪。

1.2 第一个 Rust 程序:“Hello, world!”
Cargo,Rust 开发中的得力助手,它负责项目的创建、依赖管理、构建和运行 。让我们用 Cargo 创建第一个项目:
-
创建新项目:
在终端中运行 cargo new hello_rust。Cargo 会创建一个名为 hello_rust 的目录,其中包含一个 src 文件夹和一个 Cargo.toml 文件。
-
项目结构:
- Cargo.toml:项目的配置文件,用于描述项目元数据和依赖项。
- src/main.rs:项目的源代码主文件。

-
编写代码:
打开 src/main.rs,我们将会看到 Cargo 已生成了经典的 “Hello, world!” 代码:- fn main() 是程序的入口点,所有 Rust 可执行程序都从这里开始。
- println! 是一个宏(macro),用于将文本打印到控制台。感叹号 ! 是宏调用的标志。
fn main() {
println!("Hello, world!");
}
- 编译并运行:
在 hello_rust 项目的根目录下,执行 cargo run。Cargo 会首先编译代码,然后在编译成功后运行生成的可执行文件。我们将在屏幕上看到 Hello, world! 的输出。
2. Rust 核心语法基础
掌握了环境配置后,接下来我们需要学习 Rust 的基本语法构建块。
2.1 变量与可变性(Immutability)
在 Rust 中,变量默认是不可变的。这是一个核心的安全特性,有助于减少意外的副作用。
// 声明一个不可变变量 `x`
let x = 5;
// 下面这行代码会编译失败,因为不能对不可变变量二次赋值
// x = 6;
// 如果需要一个可变变量,必须使用 `mut` 关键字
let mut y = 10;
y = 11; // 这是合法的
2.2 基本数据类型
Rust 是静态类型语言,但编译器拥有强大的类型推断能力。它主要有两类数据类型:
- 标量类型(Scalar Types):代表单个值。
- 整型(Integer):如 i32 (32位有符号整数)、u64 (64位无符号整数)。
- 浮点型(Floating-Point):f32 和 f64。
- 布尔型(Boolean):bool,值为 true 或 false。
- 字符型(Character):char,代表一个 Unicode 标量值,使用单引号 ’ '。
- 复合类型(Compound Types):将多个值组合成一个类型。
- 元组(Tuple):固定长度的、可以包含多种类型值的集合。
let tup: (i32, f64, u8) = (500, 6.4, 1); let first_value = tup.0; // 通过索引访问 - 数组(Array):固定长度的、所有元素必须是相同类型的集合。
let a = [1, 2, 3, 4, 5]; let first_element = a[[0]]; // 通过索引访问
- 元组(Tuple):固定长度的、可以包含多种类型值的集合。
2.3 函数(Functions)
函数是 Rust 代码组织的基本单位。函数定义使用 fn 关键字,参数需要明确类型,返回值类型在 -> 后指定。
// 一个接受两个 i32 类型参数并返回 i32 类型值的函数
fn add(a: i32, b: i32) -> i32 {
// Rust 中的表达式:最后一行不带分号的表达式的值将作为函数的返回值
a + b
}
2.4 控制流
Rust 的控制流结构与其他语言类似,但 match 表达式尤为强大。
- if-else 表达式:
let number = 6; if number % 4 == 0 { println!("可知此数为4的倍数"); } else if number % 3 == 0 { println!("可知此数为3的倍数"); } else { println!("啥也不是"); } - 循环(loop, while, for):
for 循环是遍历集合最常用和最安全的方式。
let collection = [10, 20, 30, 40, 50];
for item in collection.iter() {
println!("the value is: {}", item);
}
-
match 表达式:
match 类似于java中的 switch,但它要求列尽所有可能性。let status_code = 200; match status_code { 200 => println!("OK"), 404 => println!("Not Found"), 500 => println!("Internal Server Error"), // `_` 是一个通配符,匹配任何未被列出的值 _ => println!("Unknown status"), }
2.5 复合数据结构:结构体(Struct)与枚举(Enum)
-
结构体 (struct) :用于创建自定义数据类型,将相关的数据组合在一起。
struct User { username: String, email: String, active: bool, } let user1 = User { email: String::from("123@example.com"), username: String::from("username123"), active: true, }; -
枚举 (enum) :允许一个值成为一组可能的变体之一。Rust 的枚举非常强大,每个变体都可以关联不同类型和数量的数据。
enum Message { Quit, // 没有关联数据 Move { x: i32, y: i32 }, // 包含一个匿名结构体 Write(String), // 包含一个 String ChangeColor(i32, i32, i32), // 包含三个 i32 值 }
3. Rust 的灵魂——所有权系统
这是 Rust 最独特也最具挑战性的部分,但也是其内存安全保证的核心。
3.1 为何需要所有权?
在 C/C++ 等语言中,开发者需要手动管理内存(malloc/free),这很容易导致悬垂指针、二次释放等内存安全问题。而在 Java、Python 等语言中,垃圾回收器(GC)在运行时自动管理内存,但这会带来一定的性能开销。而 Rust 则采用了一种全新的方案:所有权系统。它是一组在编译时由编译器强制执行的规则,用于管理内存,既没有手动管理的风险,也没有运行时垃圾回收的开销。
3.2 所有权三大规则
- 每个值都有一个被称为其“所有者”(Owner)的变量。
- 值在任意时刻有且只有一个所有者。
- 当所有者(变量)离开作用域时,其拥有的值将被自动释放。
让我们通过一个例子来理解:
{
// s 在这里还未声明,是无效的
let s = String::from("hello"); // s 从此刻开始有效,它拥有 "hello" 这个值
// 可以对 s 进行操作
} // s 的作用域到此结束,它拥有的值被自动释放,内存被归还
当 s 拥有 String 类型的值时,如果我们将 s 赋给另一个变量 s2,就会发生 所有权转移(Move):
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权转移给了 s2
// 下面这行代码会编译失败,因为 s1 不再拥有这个值,它已经失效了
// println!("{}, world!", s1);
这个机制从根本上避免了“二次释放”的问题,因为只有一个所有者负责释放内存。
3.3 借用(Borrowing)与引用(References)
如果我们只是想使用一个值而不获取其所有权,该怎么办?这时就需要借用。我们可以创建一个指向值的 引用(Reference)。
fn main() {
let s1 = String::from("hello");
// `&s1` 创建了一个指向 s1 值的引用,但并不拥有它
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len); // s1 在这里仍然有效
}
// 函数参数 `s: &String` 表示它借用了 String 的一个引用
fn calculate_length(s: &String) -> usize {
s.len()
} // s 在这里离开作用域,但因为它不拥有值,所以什么也不会发生
借用也遵循严格的规则,这些规则同样由编译器在编译时检查:
- 在任何给定时间,你要么只能有一个可变引用(&mut T),要么只能有任意数量的不可变引用(&T)。
- 引用必须始终有效。
这个规则巧妙地防止了数据竞争——即多个指针在同一时间访问同一数据,并且至少有一个在进行写操作。
新一代开源开发者平台 GitCode,通过集成代码托管服务、代码仓库以及可信赖的开源组件库,让开发者可以在云端进行代码托管和开发。旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。
更多推荐

所有评论(0)