1. Rust入门:从零开始,理解这门语言的底气
大家好,我是你们这门课的讲师。今天咱们聊聊Rust的起点。说实话,我第一次接触Rust是在2016年,那时候它还没到1.0版本。当时我正被C++的内存泄漏搞得焦头烂额,看到Rust的宣传语——"内存安全,无需GC"——第一反应是:这玩意儿靠谱吗?
后来我花了一周时间,写了个简单的网络工具。嗯,真香。从那以后,我的主力开发语言就从C++慢慢转向了Rust。今天这第一节课,咱们就从头捋一捋:Rust到底是个啥?它凭什么能解决系统编程的老大难问题?
1.1 Rust语言发展史:一个"被迫"诞生的英雄
Rust的故事,得从Mozilla说起。2006年,Mozilla的一位工程师Graydon Hoare开始做一个个人项目。他当时想:能不能设计一门语言,既有C++的性能,又能彻底干掉内存安全问题?
2010年,Mozilla正式对外宣布了Rust项目。2015年,Rust 1.0稳定版发布。这中间经历了将近10年的打磨。为什么这么久?说白了,他们在解决一个极其困难的问题——如何在编译时就保证内存安全,同时不引入垃圾回收(GC)的性能开销。
我个人觉得,Rust的诞生有点像"被迫的"。你看,C/C++统治了系统编程几十年,但缓冲区溢出、空指针、悬垂指针这些问题,每年造成的安全漏洞不计其数。业界需要一种更安全的系统语言,但又不愿意牺牲性能。Rust就是在这个夹缝中杀出来的。
核心时间线:
- 2006年:Graydon Hoare开始个人项目
- 2010年:Mozilla正式宣布Rust
- 2015年:Rust 1.0稳定版发布
- 2021年:Rust成立独立基金会(Mozilla退出)
- 2023年:Linux内核开始支持Rust
1.2 核心特性:Rust凭什么这么"硬"?
咱们直接说重点。Rust有三个核心特性,是它区别于其他语言的"杀手锏"。
1.2.1 内存安全:没有GC,也能安全
这是Rust最引以为傲的特性。传统系统语言(C/C++)里,内存管理全靠程序员手动。你new了一个对象,就得记得delete。忘了?内存泄漏。删早了?悬垂指针。多线程里同时读写?数据竞争。
Rust的解决方案是——所有权系统(Ownership)。说白了,每个值在任意时刻只有一个"主人"。当主人离开作用域,值自动被释放。再加上借用(Borrowing)和生命周期(Lifetime)的规则,编译器在编译阶段就能检查出所有内存安全问题。
避坑指南:我曾经在一个项目中,用Rust写了一个多线程的缓存服务。刚开始觉得所有权规则太烦人,总想用unsafe绕过去。后来发现,老老实实遵循规则,代码反而更清晰,而且几乎没有运行时崩溃。相信我,编译器的报错,其实是帮你省了半夜调试的时间。
1.2.2 零成本抽象:高性能,不妥协
Rust的抽象(比如迭代器、闭包、泛型)在运行时不会产生额外开销。什么意思?你写的高层代码,编译后和手写的底层汇编一样高效。这一点,Rust和C++的理念一致——你不需要为你不用的特性付费。
举个例子,Rust的迭代器链式调用:
let sum: i32 = (1..100)
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.sum();
这段代码编译后,和手写的for循环性能完全一样。Rust的编译器会做内联、去虚拟化等优化,把抽象层"展开"成最直接的机器码。
1.2.3 无GC:掌控一切
垃圾回收(GC)虽然方便,但会带来不可预测的暂停时间。在系统编程、嵌入式、游戏引擎、实时系统中,这种暂停是致命的。Rust没有运行时,没有GC,所有资源管理都在编译期确定。这意味着你可以精确控制内存布局、分配时机,甚至能用在操作系统内核里。
注意:无GC不代表不需要管理内存。Rust的所有权系统本质上是一种"静态的内存管理"。你写代码时仍然需要考虑生命周期,但编译器会帮你检查。说白了,把运行时的问题提前到编译时解决。
1.3 安装Rust工具链:三件套搞定
要开始写Rust,你需要三个工具:rustup、cargo、rustc。我习惯用rustup来管理,因为它能轻松切换不同版本的Rust编译器。
1.3.1 安装rustup
打开终端,执行:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
或者,如果你在Windows上,去官网下载rustup-init.exe。安装完成后,重启终端,输入rustc --version,看到版本号就说明成功了。
1.3.2 工具链三件套
| 工具 | 作用 | 常用命令 |
|---|---|---|
| rustup | 管理Rust版本和工具链 | rustup update, rustup default stable |
| cargo | 包管理器和构建工具 | cargo new, cargo build, cargo run |
| rustc | Rust编译器 | rustc main.rs |
个人建议:日常开发中,你几乎不会直接使用rustc。cargo会帮你调用编译器。所以,记住cargo的命令就够了。rustup主要用于升级Rust版本或切换nightly通道。
1.4 第一个Rust程序:Hello World
咱们来写第一个程序。打开终端,创建一个新项目:
cargo new hello_world
cd hello_world
cargo会生成一个目录结构。打开src/main.rs,你会看到:
fn main() {
println!("Hello, world!");
}
运行它:
cargo run
你会看到终端输出"Hello, world!"。就这么简单。
这里解释一下:fn main()是程序的入口点。println!是一个宏(注意后面的感叹号),用于打印文本到控制台。Rust里,宏和函数不同,宏可以接受可变数量的参数,并且会在编译时展开。
1.5 Cargo项目结构解析:不只是"Hello World"
刚才cargo new生成了什么?咱们看看:
hello_world/
├── Cargo.toml
├── src/
│ └── main.rs
└── .gitignore
这个结构很清晰。我来解释每个文件的作用:
- Cargo.toml:项目的配置文件。类似Node.js的package.json或Rust的Cargo.toml。里面定义了项目名、版本、依赖等。
- src/main.rs:源代码文件。Rust的约定是,可执行程序的入口在
src/main.rs,库的入口在src/lib.rs。 - .gitignore:Git忽略文件,默认忽略
target/目录(编译产物)。
打开Cargo.toml看看:
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
这里edition = "2021"指定了Rust的版本版次。Rust每三年发布一个大版本,2021版是当前稳定版。你想想看,这个设计其实很聪明——语言在进化,但旧项目不会因为升级编译器而崩溃。
重要概念:cargo build编译后的产物放在target/debug/目录下。如果你想要发布版本,用cargo build --release,产物在target/release/。release模式会启用更多优化,编译时间更长,但运行速度更快。
知识体系总览
下面这张图,帮你把本章的核心知识点串起来:
好了,这就是第一章的全部内容。从Rust的诞生背景,到它的核心设计理念,再到实际安装和第一个程序。你想想看,其实Rust并没有那么神秘——它只是把C++程序员踩过的坑,提前在编译期帮你堵上了。
下一章,咱们会深入Rust的语法基础:变量、数据类型、函数和控制流。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。