Rust入门:从零到精通

Rust作为一门现代系统编程语言,正以其卓越的内存安全性和高性能特性改变着编程世界的格局。本文将为你提供一份系统性的Rust学习路线图。
前言:为什么选择Rust?
在开始具体的学习之前,我们有必要了解Rust语言的独特价值。Rust由Mozilla研究院开发,自2015年发布1.0版本以来,迅速获得了开发者的广泛认可。它连续多年在Stack Overflow开发者调查中被评为"最受喜爱的编程语言"。
Rust的核心优势:
- 内存安全:在编译时就能防止空指针解引用、缓冲区溢出等常见内存错误
- 零成本抽象:提供高级语言特性的同时,不带来运行时性能开销
- fearless concurrency:让并发编程更加安全,避免数据竞争
- 丰富的生态系统:通过Cargo和crates.io拥有强大的包管理生态
第一章:入门指南
1.1 安装Rust
Windows系统安装:
- 访问Rust官网
- 下载并运行
rustup-init.exe - 按照提示完成安装,建议选择默认选项
- 安装完成后,重启命令行终端
验证安装:
rustc --version
cargo --version
Linux/macOS系统安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
1.2 你好,世界!
创建你的第一个Rust程序:
// main.rs
fn main() {
println!("Hello, World!");
}
编译和运行:
rustc main.rs
./main
代码解析:
fn main():程序入口点,所有可执行Rust程序都必须有main函数println!:这是一个宏(注意感叹号),用于向标准输出打印文本- 分号
;:Rust语句以分号结尾
1.3 你好,Cargo!
Cargo是Rust的构建系统和包管理器,类似于Node.js的npm或Python的pip。
创建新项目:
cargo new hello_cargo
cd hello_cargo
项目结构:
hello_cargo/
├── Cargo.toml
└── src
└── main.rs
Cargo.toml文件说明:
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <your.email@example.com>"]
edition = "2021"
[dependencies]
常用Cargo命令:
cargo build # 编译项目
cargo run # 编译并运行
cargo check # 检查代码编译是否通过,但不生成可执行文件
cargo build --release # 发布构建
第二章:编写猜谜游戏
这个实战项目将综合运用多个基础概念:
use std::io;
use rand::Rng;
use std::cmp::Ordering;
fn main() {
println!("猜数字游戏!");
let secret_number = rand::thread_rng().gen_range(1..101);
loop {
println!("请输入你的猜测:");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("读取行失败");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("你猜测的是:{}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("太小了!"),
Ordering::Greater => println!("太大了!"),
Ordering::Equal => {
println!("恭喜你,猜对了!");
break;
}
}
}
}
需要添加依赖到Cargo.toml:
[dependencies]
rand = "0.8.5"
项目学习要点:
- 使用外部crate(rand)
- 变量声明和可变性
- 用户输入处理
- 错误处理
- 模式匹配
- 循环控制
第三章:常见的编程概念
3.1 变量和可变性
不可变变量:
let x = 5;
// x = 6; // 这行会编译错误,因为x是不可变的
可变变量:
let mut x = 5;
x = 6; // 这是允许的
常量:
const MAX_POINTS: u32 = 100_000;
变量遮蔽:
let x = 5;
let x = x + 1; // 遮蔽第一个x
let x = x * 2; // 遮蔽第二个x
println!("x的值是:{}", x); // 输出12
3.2 数据类型
标量类型:
// 整数类型
let a: i32 = -100; // 有符号32位整数
let b: u64 = 200; // 无符号64位整数
// 浮点类型
let c: f32 = 3.14; // 32位浮点数
let d: f64 = 2.71828; // 64位浮点数
// 布尔类型
let e: bool = true;
// 字符类型
let f: char = '🚀'; // Unicode标量值
复合类型:
// 元组
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 解构
let five_hundred = tup.0; // 通过索引访问
// 数组
let arr = [1, 2, 3, 4, 5];
let first = arr[0];
let months = ["January", "February", "March"];
3.3 函数
函数定义和调用:
fn main() {
let result = add_numbers(5, 3);
println!("结果是:{}", result);
}
fn add_numbers(x: i32, y: i32) -> i32 {
x + y // 注意没有分号,这是表达式返回值
}
语句与表达式:
fn example() {
let y = { // 代码块是一个表达式
let x = 3;
x + 1 // 没有分号,返回x+1的值
};
println!("y的值是:{}", y); // 输出4
}
3.4 注释
// 这是单行注释
/*
这是
多行注释
*/
/// 这是文档注释,用于生成HTML文档
/// # 示例
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
fn add(a: i32, b: i32) -> i32 {
a + b
}
3.5 控制流
if表达式:
let number = 6;
if number % 4 == 0 {
println!("能被4整除");
} else if number % 3 == 0 {
println!("能被3整除");
} else {
println!("不能被4或3整除");
}
// if是表达式,可以用于赋值
let condition = true;
let number = if condition { 5 } else { 6 };
循环:
// loop循环
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
// while循环
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
// for循环遍历集合
let arr = [10, 20, 30, 40, 50];
for element in arr.iter() {
println!("值是:{}", element);
}
// for循环范围
for number in 1..4 { // 1, 2, 3
println!("{}!", number);
}
第四章:理解所有权
所有权是Rust最独特的特性,也是其内存安全的核心保障。
4.1 什么是所有权?
所有权规则:
- Rust中的每一个值都有一个被称为其所有者的变量
- 值在任一时刻有且只有一个所有者
- 当所有者离开作用域,这个值将被丢弃
变量作用域示例:
{ // s 在这里无效,它尚未声明
let s = "hello"; // 从此处起,s是有效的
// 使用 s
} // 此作用域已结束,s不再有效
String类型的内存分配:
{
let s = String::from("hello"); // 在堆上分配内存
// 使用 s
} // 自动调用drop函数释放内存
移动语义:
let s1 = String::from("hello");
let s2 = s1; // s1的所有权移动到s2,s1不再有效
// println!("{}", s1); // 这行会编译错误!
克隆数据:
let s1 = String::from("hello");
let s2 = s1.clone(); // 深度拷贝堆数据
println!("s1 = {}, s2 = {}", s1, s2); // 两者都有效
4.2 引用和借用
不可变引用:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 传递引用,不获取所有权
println!("'{}'的长度是{}", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s离开作用域,但因为不拥有所有权,不会drop任何东西
可变引用:
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("修改后:{}", s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
引用规则:
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
- 引用必须总是有效的
4.3 切片类型
字符串切片:
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
let whole = &s[..]; // 整个字符串
// 字符串字面值就是切片
let literal: &str = "Hello, world!";
函数使用字符串切片:
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
fn main() {
let my_string = String::from("hello world");
let word = first_word(&my_string[..]);
println!("第一个单词:{}", word);
let my_string_literal = "hello world";
let word = first_word(my_string_literal);
println!("第一个单词:{}", word);
}
数组切片:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // 类型是&[i32],包含[2, 3]
开始你的Rust之旅吧! 记住,Rust的学习曲线可能比较陡峭,但一旦掌握,你将获得编写安全高效系统代码的强大能力。如果在学习过程中遇到困难,Rust社区以其友好和热情著称,随时欢迎寻求帮助。
Happy coding in Rust! 🦀
版权声明:本教程仅供学习使用,转载请注明出处。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)