Rust 语言入门博客

这是一篇从零开始的详细指南,涵盖核心概念、所有权系统、实战示例等内容。


🦀 Rust 语言入门完全指南:从零开始掌握系统级编程

"Rust 是一门赋予每个人构建可靠且高效软件能力的语言。"

目录

  1. [为什么选择 Rust?](#为什么选择 Rust? "#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-rust")
  2. 环境搭建
  3. 基础语法速览
  4. 核心概念:所有权系统
  5. 结构体与枚举
  6. 错误处理
  7. [实战:构建 CLI 工具](#实战:构建 CLI 工具 "#%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-cli-%E5%B7%A5%E5%85%B7")
  8. 学习资源推荐

为什么选择 Rust?

Rust 自 2015 年发布 1.0 版本以来,连续八年被 Stack Overflow 评为最受开发者喜爱的编程语言。它的核心优势在于:

特性 说明
内存安全 编译时检查,无需垃圾回收器 (GC)
零成本抽象 高级特性不牺牲运行时性能
并发安全 编译期防止数据竞争
现代工具链 Cargo 包管理、内置测试、文档生成

适用场景:系统编程、WebAssembly、嵌入式开发、高性能网络服务、区块链基础设施等。


环境搭建

安装 Rustup(官方推荐方式)

bash 复制代码
# Linux/macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Windows
# 下载并运行 https://win.rustup.rs/

安装完成后,验证环境:

bash 复制代码
rustc --version  # 查看编译器版本
cargo --version  # 查看包管理器版本

第一个程序:Hello, World!

创建项目:

bash 复制代码
cargo new hello_rust
cd hello_rust

src/main.rs 内容:

rust 复制代码
fn main() {
    println!("Hello, Rustaceans! 🦀");
}

运行:

bash 复制代码
cargo run

💡 提示Cargo 是 Rust 的构建系统和包管理器,类比 Python 的 pip + setuptools,或 Node.js 的 npm。


基础语法速览

变量与可变性

rust 复制代码
fn main() {
    // 不可变变量(默认)
    let x = 5;
    // x = 6; // 错误!不能修改不可变变量
    
    // 可变变量
    let mut y = 5;
    y = 6; // ✅ 合法
    
    // 常量(编译期确定,必须标注类型)
    const MAX_POINTS: u32 = 100_000;
    
    // 遮蔽(Shadowing)- 允许同名变量
    let spaces = "   ";
    let spaces = spaces.len(); // 类型从 &str 变为 usize
}

数据类型

rust 复制代码
fn main() {
    // 标量类型
    let a: i32 = -42;        // 有符号整数
    let b: u64 = 100;        // 无符号整数
    let c: f64 = 3.14159;    // 浮点数
    let d: bool = true;      // 布尔值
    let e: char = 'ℤ';       // Unicode 字符(4字节)
    
    // 复合类型:元组
    let tup: (i32, f64, &str) = (500, 6.4, "hi");
    let (x, y, z) = tup;     // 解构
    let five_hundred = tup.0; // 索引访问
    
    // 复合类型:数组(固定长度)
    let arr = [1, 2, 3, 4, 5];
    let first = arr[0];
    
    // 动态数组(Vec,在堆上分配)
    let mut vec = vec![1, 2, 3];
    vec.push(4);
}

函数与控制流

rust 复制代码
fn main() {
    let result = add(5, 3);
    println!("5 + 3 = {}", result);
    
    // if 表达式(注意:不是语句,返回值为表达式结果)
    let number = 6;
    let condition = if number % 2 == 0 { "偶数" } else { "奇数" };
    
    // 循环
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2; // 返回值
        }
    };
    
    // while 循环
    while counter > 0 {
        println!("{}!", counter);
        counter -= 1;
    }
    
    // for 循环(推荐,安全且高效)
    for number in 1..4 {
        println!("{}!", number);
    }
}

// 函数定义:参数需标注类型,返回值类型在箭头后
fn add(a: i32, b: i32) -> i32 {
    a + b  // 注意:无分号表示表达式返回值,等同于 return a + b;
}

核心概念:所有权系统

所有权 (Ownership) 是 Rust 最独特的特性,它让 Rust 无需垃圾回收器就能保证内存安全。

三条黄金规则

  1. 每个值都有一个所有者 (owner)
  2. 同一时间只能有一个所有者
  3. 所有者离开作用域,值被丢弃

所有权转移(Move)

rust 复制代码
fn main() {
    let s1 = String::from("hello");  // s1 拥有这个字符串
    let s2 = s1;                      // 所有权转移给 s2
    
    // println!("{}", s1); // ❌ 错误!s1 不再有效
    
    // 深拷贝(Clone)
    let s3 = s2.clone();
    println!("s2 = {}, s3 = {}", s2, s3); // ✅ 两者都可用
}

借用(Borrowing)

使用引用 & 借用值,而不获取所有权:

rust 复制代码
fn main() {
    let s = String::from("hello");
    
    // 不可变借用
    let len = calculate_length(&s);
    println!("'{}' 的长度是 {}", s, len); // ✅ s 仍然有效
    
    // 可变借用
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s); // 输出 "hello, world"
}

fn calculate_length(s: &String) -> usize {
    s.len()
} // s 在这里离开作用域,但不拥有所有权,所以不会 drop

fn change(s: &mut String) {
    s.push_str(", world");
}

借用规则(编译器强制执行)

  • 要么 一个可变引用 &mut T
  • 要么 任意数量的不可变引用 &T
  • 不能同时存在
rust 复制代码
let mut s = String::from("hello");

let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // ❌ 大错误!不能同时拥有不可变和可变引用

println!("{}, {}, and {}", r1, r2, r3);

Slice 类型

不持有所有权的数据引用,常用于字符串切片:

rust 复制代码
fn main() {
    let s = String::from("hello world");
    
    let hello = &s[0..5];  // 字符串切片
    let world = &s[6..11];
    
    // 更好的 first_word 函数
    let word = first_word(&s);
    println!("第一个单词是: {}", word);
}

fn first_word(s: &str) -> &str {  // &str 是字符串切片类型
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]
}

结构体与枚举

结构体定义

rust 复制代码
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main() {
    // 创建实例
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    
    // 结构体更新语法
    let user2 = User {
        email: String::from("another@example.com"),
        ..user1 // 其余字段从 user1 获取
    };
    
    // 元组结构体
    struct Point(i32, i32, i32);
    let origin = Point(0, 0, 0);
}

方法定义

rust 复制代码
#[derive(Debug)] // 自动派生 Debug trait,支持打印
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 构造函数(约定俗成叫 new,但不是关键字)
    fn new(width: u32, height: u32) -> Self {
        Rectangle { width, height }
    }
    
    // 方法:第一个参数是 self(&self, &mut self 或 self)
    fn area(&self) -> u32 {
        self.width * self.height
    }
    
    // 关联函数(静态方法):没有 self 参数
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}

fn main() {
    let rect = Rectangle::new(30, 50);
    println!("面积: {}", rect.area());
    
    let sq = Rectangle::square(3);
    println!("{:?}", sq); // 使用 Debug 格式打印
}

枚举与模式匹配

rust 复制代码
enum Message {
    Quit,                           // 无数据
    Move { x: i32, y: i32 },        // 匿名结构体
    Write(String),                  // 单个值
    ChangeColor(i32, i32, i32),     // 元组
}

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("Quit"),
            Message::Move { x, y } => println!("Move to x: {}, y: {}", x, y),
            Message::Write(text) => println!("Text: {}", text),
            Message::ChangeColor(r, g, b) => println!("Color: {}, {}, {}", r, g, b),
        }
    }
}

// Option 枚举(Rust 没有 null!)
enum Option<T> {
    Some(T),
    None,
}

fn main() {
    let some_number = Some(5);
    let absent_number: Option<i32> = None;
    
    // match 必须穷举所有可能
    let coin = Message::Quit;
    coin.call();
    
    // if let 简化匹配(只关心一种模式)
    if let Message::Quit = coin {
        println!("是 Quit 消息");
    }
}

错误处理

Rust 将错误分为两类:可恢复错误Result<T, E>)和不可恢复错误panic!)。

Result 类型

rust 复制代码
use std::fs::File;
use std::io::{self, Read};

fn main() {
    // 手动处理
    let f = File::open("hello.txt");
    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("打开文件失败: {:?}", error),
    };
    
    // 简写:unwrap(失败时 panic)和 expect(带自定义消息)
    let f = File::open("hello.txt").expect("无法打开 hello.txt");
    
    // ? 运算符:错误传播
    let content = read_username_from_file().expect("读取失败");
}

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;  // 如果 Err,直接返回
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

// 更简洁的写法
fn read_username_from_file_v2() -> Result<String, io::Error> {
    std::fs::read_to_string("hello.txt")
}

实战:构建 CLI 工具

让我们用 Rust 构建一个实用的命令行工具:文件内容搜索工具(简化版 grep)。

项目结构

bash 复制代码
cargo new minigrep
cd minigrep

完整代码

Cargo.toml

toml 复制代码
[package]
name = "minigrep"
version = "0.1.0"
edition = "2021"

[dependencies]
colored = "2.0"  # 添加彩色输出依赖

src/main.rs

rust 复制代码
use std::env;
use std::fs;
use std::process;
use colored::*;

struct Config {
    query: String,
    file_path: String,
    ignore_case: bool,
}

impl Config {
    fn build(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("用法: minigrep <查询字符串> <文件路径>");
        }
        
        let query = args[1].clone();
        let file_path = args[2].clone();
        let ignore_case = env::var("IGNORE_CASE").is_ok();
        
        Ok(Config { query, file_path, ignore_case })
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    
    let config = Config::build(&args).unwrap_or_else(|err| {
        eprintln!("参数错误: {}", err);
        process::exit(1);
    });
    
    println!("搜索: {}", config.query.green());
    println!("文件: {}", config.file_path.blue());
    
    if let Err(e) = run(config) {
        eprintln!("应用错误: {}", e);
        process::exit(1);
    }
}

fn run(config: Config) -> Result<(), Box<dyn std::error::Error>> {
    let contents = fs::read_to_string(&config.file_path)?;
    
    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    } else {
        search(&config.query, &contents)
    };
    
    for line in results {
        println!("{}", line.red());
    }
    
    Ok(())
}

fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.contains(query))
        .collect()
}

fn search_case_insensitive<'a>(
    query: &str,
    contents: &'a str,
) -> Vec<&'a str> {
    let query = query.to_lowercase();
    contents
        .lines()
        .filter(|line| line.to_lowercase().contains(&query))
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn case_sensitive() {
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }

    #[test]
    fn case_insensitive() {
        let query = "rUsT";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
        assert_eq!(
            vec!["Rust:", "Trust me."],
            search_case_insensitive(query, contents)
        );
    }
}

运行与测试

bash 复制代码
# 构建并运行
cargo run -- "test" poem.txt

# 运行测试
cargo test

# 发布构建(优化性能)
cargo build --release

学习资源推荐

官方资源

中文社区

进阶书籍

  • 《Programming Rust》 - 系统深入
  • 《Rust Atomics and Locks》 - 并发编程
  • 《Zero To Production In Rust》 - 后端实战

实践建议

  1. 先理解所有权:这是 Rust 的门槛,也是精髓。建议画内存图辅助理解。
  2. 善用编译器:Rust 编译器的错误提示非常友好,仔细阅读建议。
  3. 从项目中学:尝试用 Rust 重写你熟悉的工具,如 HTTP 客户端、爬虫等。
  4. 参与社区 :Rust 社区非常友好,遇到问题可以在 users.rust-lang.org 提问。

总结

Rust 的学习曲线确实比大多数语言陡峭,但这是为了换取编译期的安全保证运行时的零成本。一旦掌握所有权系统,你将获得:

  • 不再担心空指针、野指针、数据竞争
  • 高性能的代码(媲美 C/C++)
  • 现代化的工具链和包管理
  • 可靠的并发编程能力

正如 Rust 的口号所说:"Fearless Concurrency"(无畏并发)。开始你的 Rust 之旅吧!🦀


作者注:本文代码均在 Rust 1.75+ 版本测试通过。如有疑问或建议,欢迎在评论区留言交流。


: Stack Overflow Developer Survey 2023 - Most Loved Languages : The Rust Programming Language - doc.rust-lang.org/book/ : Rust语言圣经 - course.rs/

相关推荐
本地化文档2 小时前
rustdoc-book-l10n
rust·github·gitcode
Tony Bai5 小时前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
jump_jump6 小时前
RTK:给 AI 编码助手瘦身的 Rust 代理
性能优化·rust·claude
小杍随笔11 小时前
【Rust Exercism 练习详解:Anagram + Space Age + Sublist(附完整代码与深度解读)】
开发语言·rust·c#
Rust研习社13 小时前
Rust 字符串与切片实战
rust
朝阳58113 小时前
局域网聊天工具
javascript·rust
朝阳58113 小时前
我做了一个局域网传文件的小工具,记录一下
javascript·rust
Rust语言中文社区1 天前
【Rust日报】用 Rust 重写的 Turso 是一个更好的 SQLite 吗?
开发语言·数据库·后端·rust·sqlite
小杍随笔1 天前
【Rust 半小时速成(2024 Edition 更新版)】
开发语言·后端·rust
Source.Liu1 天前
【office2pdf】office2pdf 纯 Rust 实现的 Office 转 PDF 库
rust·pdf·office2pdf