Rust编程语言入门

🏷️ L1 📊 beginner ⏱️ 45分钟 🏷️ free,Rust,系统编程,所有权,借用,Cargo,CLI,前沿

# Rust编程语言入门

一、概述

为什么要学习Rust

Rust是一门系统级编程语言,由Mozilla研究院开发,连续多年在Stack Overflow开发者调查中被评为“最受喜爱的编程语言”。它的核心优势在于内存安全零成本抽象并发安全。在实际应用中,Rust被广泛用于:

学完本课程能做什么

1. 理解Rust所有权与借用机制,写出安全无内存泄漏的代码 2. 使用结构体与枚举构建自定义数据类型 3. 掌握模式匹配优雅地处理复杂逻辑分支 4. 运用Cargo包管理工具创建、构建和发布项目 5. 开发一个简单的CLI工具(如文件统计工具)

适合人群与前置知识

---

二、核心知识点

模块1:所有权与借用

原理讲解

Rust的所有权系统是其最独特的特性。每个值在Rust中都有一个所有者,且同一时间只能有一个所有者。当所有者离开作用域,值会被自动释放。这种机制避免了垃圾回收器的性能开销,同时保证了内存安全。

核心规则

代码示例


fn main() {
// 所有权移动
let s1 = String::from("hello");
let s2 = s1; // s1的所有权移动到s2
// println!("{}", s1); // 编译错误!s1已失效

// 借用(引用) let s3 = String::from("world"); let len = calculate_length(&s3); // 不可变借用 println!("'{}'的长度是{}", s3, len);

// 可变借用 let mut s4 = String::from("Rust"); change(&mut s4); // 可变借用 println!("修改后:{}", s4); }

fn calculate_length(s: &String) -> usize { s.len() // 借用不获取所有权 }

fn change(s: &mut String) { s.push_str(" is awesome"); }


关键技术对比

| 特性 | 所有权转移 | 不可变借用 | 可变借用 | |------|-----------|-----------|---------| | 语法 | let b = a; | &T | &mut T | | 所有权 | 转移 | 保留 | 保留 | | 可修改 | 仅新所有者可修改 | 不可修改 | 可修改 | | 同时存在 | 仅一个所有者 | 多个 | 仅一个 |

---

模块2:结构体与枚举

原理讲解

结构体(struct)和枚举(enum)是Rust中定义自定义数据类型的主要方式。结构体将相关数据组合在一起,而枚举允许一个值可以是几种不同类型中的一种。

代码示例


// 定义结构体
struct Book {
title: String,
author: String,
pages: u32,
is_available: bool,
}

// 定义枚举 enum BookStatus { Available, Borrowed(String), // 带数据的变体 Reserved { date: String, user: String }, // 具名字段变体 }

// 为结构体实现方法 impl Book { fn new(title: &str, author: &str, pages: u32) -> Book { Book { title: String::from(title), author: String::from(author), pages, is_available: true, } }

fn display(&self) { println!("《{}》 by {}", self.title, self.author); } }

fn main() { let book = Book::new("Rust编程之道", "张三", 350); book.display();

let status = BookStatus::Borrowed(String::from("李四")); // 后续可用模式匹配处理status }


---

模块3:模式匹配

原理讲解

模式匹配是Rust中强大的控制流工具,可以解构数据结构、匹配枚举变体、处理Option<T>Result<T, E>类型。match表达式必须覆盖所有可能性,否则编译器会报错。

代码示例


enum Coin {
Penny,
Nickel,
Dime,
Quarter(String), // 带州名的Quarter
}

fn value_in_cents(coin: Coin) -> u8 { match coin { Coin::Penny => { println!("幸运便士!"); 1 } Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter(state) => { println!("来自{}的25美分", state); 25 } } }

// 使用if let简化单模式匹配 fn main() { let coin = Coin::Quarter(String::from("California")); let value = value_in_cents(coin); println!("价值:{}美分", value);

// 处理Option<T> let some_value = Some(3); if let Some(x) = some_value { println!("值为:{}", x); } }


---

模块4:错误处理与Cargo包管理

原理讲解

Rust的错误处理分为可恢复错误(Result<T, E>)和不可恢复错误(panic!)。Result枚举有两个变体:Ok(T)表示成功,Err(E)表示失败。

Cargo是Rust的构建系统和包管理器,负责依赖管理、编译、测试和文档生成。

代码示例


use std::fs::File;
use std::io::{self, Read};

// 使用Result处理错误 fn read_username_from_file() -> Result<String, io::Error> { let mut file = File::open("hello.txt")?; // ?运算符自动传播错误 let mut username = String::new(); file.read_to_string(&mut username)?; Ok(username) }

// Cargo.toml示例 // [package] // name = "my_cli_tool" // version = "0.1.0" // edition = "2021" // // [dependencies] // serde = { version = "1.0", features = ["derive"] } // clap = "4.0"

fn main() { match read_username_from_file() { Ok(name) => println!("用户名:{}", name), Err(e) => eprintln!("读取失败:{}", e), } }


---

三、实操步骤:开发一个文件统计CLI工具

步骤1:创建新项目


# 创建项目
cargo new file_stats
cd file_stats

步骤2:添加依赖

编辑Cargo.toml

[package]
name = "file_stats"
version = "0.1.0"
edition = "2021"

[dependencies] clap = { version = "4.0", features = ["derive"] }


步骤3:编写主程序

src/main.rs

use clap::Parser;
use std::fs::File;
use std::io::{BufRead, BufReader};

#[derive(Parser)] #[command(name = "file_stats")] #[command(about = "统计文件的行数、单词数和字符数")] struct Cli { #[arg(help = "要统计的文件路径")] file_path: String, }

fn main() { let cli = Cli::parse(); let file = File::open(&cli.file_path).expect("无法打开文件"); let reader = BufReader::new(file);

let mut line_count = 0; let mut word_count = 0; let mut char_count = 0;

for line in reader.lines() { let line = line.expect("读取行失败"); line_count += 1; word_count += line.split_whitespace().count(); char_count += line.chars().count(); }

println!("文件: {}", cli.file_path); println!("行数: {}", line_count); println!("单词数: {}", word_count); println!("字符数: {}", char_count); }


步骤4:构建和运行


# 构建项目
cargo build --release

# 运行程序 ./target/release/file_stats Cargo.toml


预期输出


文件: Cargo.toml
行数: 10
单词数: 25
字符数: 180

---

四、常见问题与故障排查

问题1:编译错误“borrow of moved value”

原因:尝试使用已移动所有权的变量 解决:使用引用(&)而不是移动,或克隆值

let s1 = String::from("hello");
let s2 = s1.clone(); // 克隆而不是移动
println!("{} {}", s1, s2); // 正常工作

问题2:同时存在多个可变引用

原因:Rust不允许同时存在多个可变引用 解决:使用代码块限制作用域

let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1作用域结束
let r2 = &mut s; // 现在可以创建新可变引用

问题3:`match`没有覆盖所有情况

原因:模式匹配必须穷举所有可能性 解决:使用通配符_处理剩余情况

match x {
1 => println!("one"),
2 => println!("two"),
_ => println!("其他"), // 通配符分支
}

问题4:Cargo依赖下载失败

原因:网络问题或Cargo镜像配置 解决:配置国内镜像源

# 在~/.cargo/config.toml中添加
[source.crates-io]
replace-with = 'ustc'

[source.ustc] registry = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/"


---

五、总结与扩展

重点知识回顾

1. 所有权三原则:每个值只有一个所有者,所有权可移动,所有者离开作用域值被释放 2. 借用规则:任意时刻要么有一个可变引用,要么有多个不可变引用 3. 模式匹配match必须穷举,if let适合单模式匹配 4. 错误处理:优先使用Result<T, E>处理可恢复错误,?运算符简化错误传播 5. Cargo工作流cargo new创建项目,cargo build编译,cargo run运行

实战最佳实践

  • 编写代码时优先使用`String`和`Vec<T>`,它们拥有所有权
  • 函数参数优先使用引用(`&T`)而不是获取所有权
  • 使用`cargo clippy`进行代码审查,`cargo fmt`格式化代码
  • 为每个`Result`和`Option`值显式处理错误,避免使用`unwrap()`
  • 使用`#[derive(Debug)]`为自定义类型自动实现调试输出

进一步学习方向

1. 进阶概念:生命周期标注、智能指针(Box<T>Rc<T>RefCell<T>)、闭包与迭代器 2. 并发编程std::threadstd::sync模块、async/await异步编程 3. Web开发:使用Actix-webRocket框架构建Web应用 4. 系统编程:FFI(外部函数接口)、裸指针操作、内联汇编 5. 推荐资源
  • 《Rust程序设计语言》(The Rust Programming Language)
  • 《Rust实战》(Rust in Action)
  • Rust官方文档:https://doc.rust-lang.org/
  • Rustlings练习:https://github.com/rust-lang/rustlings

在博海学习网开始学习 →