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/

相关推荐
DongLi012 天前
rustlings 学习笔记 -- exercises/06_move_semantics
rust
ssshooter2 天前
Tauri 踩坑 appLink 修改后闪退
前端·ios·rust
布列瑟农的星空2 天前
前端都能看懂的rust入门教程(二)——函数和闭包
前端·后端·rust
蚂蚁背大象3 天前
Rust 所有权系统是为了解决什么问题
后端·rust
布列瑟农的星空3 天前
前端都能看懂的rust入门教程(五)—— 所有权
rust
Java水解4 天前
Rust嵌入式开发实战——从ARM裸机编程到RTOS应用
后端·rust
Pomelo_刘金4 天前
Rust:所有权系统
rust
Ranger09294 天前
鸿蒙开发新范式:Gpui
rust·harmonyos
DongLi017 天前
rustlings 学习笔记 -- exercises/05_vecs
rust