Rust 语言学习教程
Rust 是一门系统级编程语言,它专注于性能、安全性和并发性。无论是写操作系统、编写网络服务,还是编写嵌入式应用,Rust 都是一个非常强大的工具。在这篇教程中,我们将介绍 Rust 的基础知识,并提供一些进阶的实践示例,帮助您从入门到精通。
安装 Rust
首先,您需要安装 Rust 语言。Rust 提供了一个名为 Rustup
的工具,它可以帮助您安装和管理 Rust 的版本。通过以下命令在终端中安装 Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装完成后,您可以通过以下命令检查 Rust 是否安装成功:
rustc --version
此命令会返回您安装的 Rust 版本。
基础语法
Rust 语言的基础语法非常简洁,下面是一些基本的示例:
// 打印 "Hello, World!"
fn main() {
println!("Hello, World!");
}
注释
Rust 支持两种类型的注释:
- 单行注释:
// 这是一个单行注释
- 多行注释:
/* 这是一个多行注释 */
fn main() {
// 这行是单行注释
println!("Hello, World!"); // 输出内容
}
控制流
条件语句
Rust 使用 if
和 else
进行条件判断:
fn main() {
let number = 10;
if number > 5 {
println!("Greater than 5");
} else {
println!("Less than or equal to 5");
}
}
循环
Rust 提供了三种循环:loop
,while
和 for
。
loop
:无限循环,通常结合break
使用。
fn main() {
let mut counter = 0;
loop {
counter += 1;
if counter == 5 {
break; // 退出循环
}
}
}
while
:当条件为真时继续循环。
fn main() {
let mut number = 5;
while number != 0 {
println!("{}", number);
number -= 1;
}
}
for
:迭代集合(例如数组、范围等)。
fn main() {
for i in 1..6 {
println!("{}", i);
}
}
数据类型和变量
Rust 是一门强类型语言,这意味着您必须声明变量的类型或让编译器推断出类型。
变量
默认情况下,Rust 中的变量是不可变的。如果想要创建可变变量,使用 mut
关键字。
fn main() {
let x = 5; // 不可变
let mut y = 10; // 可变
y += 5;
println!("{}", y); // 输出 15
}
基本数据类型
Rust 支持多种数据类型,包括整数、浮点数、布尔值、字符和元组等。
- 整数:
i32
,u32
,i64
等。 - 浮点数:
f32
,f64
。 - 布尔值:
bool
。 - 字符:
char
(支持 Unicode 字符)。 - 元组:可以存储多种不同类型的数据。
fn main() {
let int: i32 = 10;
let float: f64 = 10.5;
let boolean: bool = true;
let char: char = 'A';
let tuple: (i32, f64, bool) = (10, 10.5, true);
println!("{:?}", tuple); // 输出 (10, 10.5, true)
}
所有权与借用
Rust 的独特之处在于它的所有权和借用系统。它通过这些机制来管理内存,以保证程序不会出现悬挂指针或内存泄漏。
所有权
每个值都有一个所有者,并且每个值只能有一个所有者。值可以在函数之间传递,但一旦所有权转移,原始所有者将不再能够访问该值。
fn main() {
let s1 = String::from("Hello");
let s2 = s1; // s1 的所有权转移到 s2,s1 不再有效
// println!("{}", s1); // 编译错误
}
借用
Rust 允许借用数据的不可变或可变引用,而不转移所有权。不可变引用允许读取数据,但不能修改;可变引用允许修改数据。
fn main() {
let s1 = String::from("Hello");
let s2 = &s1; // 不可变借用
println!("{}", s2); // 输出 "Hello"
}
结构体与枚举
结构体
结构体是将相关数据组合在一起的一种方式。您可以通过 struct
关键字定义结构体。
struct Person {
name: String,
age: u32,
}
fn main() {
let person = Person {
name: String::from("Alice"),
age: 30,
};
println!("Name: {}, Age: {}", person.name, person.age);
}
枚举
枚举用于表示一组可能的选项。它可以非常强大,支持复杂的数据结构。
enum Direction {
Up,
Down,
Left,
Right,
}
fn main() {
let direction = Direction::Up;
match direction {
Direction::Up => println!("Moving Up"),
Direction::Down => println!("Moving Down"),
_ => println!("Moving in other direction"),
}
}
模式匹配
Rust 提供了强大的模式匹配功能,您可以使用 match
来匹配不同的模式。
fn main() {
let number = 7;
match number {
1 => println!("One"),
2 => println!("Two"),
3 => println!("Three"),
_ => println!("Other"), // `_` 匹配其他所有情况
}
}
错误处理
Rust 使用 Result
和 Option
类型进行错误处理,而不是使用异常机制。
Result
Result
类型用于表示可能成功或失败的操作。
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Cannot divide by zero"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(10, 0) {
Ok(result) => println!("Result: {}", result),
Err(error) => println!("Error: {}", error),
}
}
Option
Option
类型表示一个值可能存在也可能不存在。
fn find_item(items: &[i32], target: i32) -> Option<usize> {
for (index, &item) in items.iter().enumerate() {
if item == target {
return Some(index);
}
}
None
}
fn main() {
let items = [1, 2, 3, 4];
match find_item(&items, 3) {
Some(index) => println!("Item found at index: {}", index),
None => println!("Item not found"),
}
}
进阶实践
并发编程
Rust 提供了内建的并发支持,它的所有权和借用系统确保了并发编程时的内存安全。以下是一个使用线程的示例:
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("Hello from a thread!");
});
handle.join().unwrap(); // 等待线程完成
}
内存管理
Rust 的所有权系统自动管理内存,避免了手动分配和回收内存的复杂性。您可以通过 Box
来管理堆上的数据。
fn main() {
let x = Box::new(5);
println!("{}", x);
}
异步编程(async/await)
Rust 的异步编程基于 async 和 await 关键字,结合 Future 特质实现,适合处理网络请求、文件操作等IO密集型任务。
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
async_task().await;
}
async fn async_task() {
println!("开始异步任务");
sleep(Duration::from_secs(2)).await;
println!("异步任务完成");
}
关键点:
- 需要借助异步运行时(如 Tokio、async-std)
- 异步函数返回实现了 Future trait 的类型
- 使用
.await
挂起等待 Future 结果
宏(Macros)
宏是 Rust 的元编程利器,允许你编写代码生成代码,提高复用和抽象能力。
声明宏示例:
macro_rules! say_hello {
() => {
println!("Hello, Rust macro!");
};
}
fn main() {
say_hello!();
}
带参数的宏示例:
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("You called {:?}()", stringify!($func_name));
}
};
}
create_function!(foo);
fn main() {
foo();
}
Trait 高级用法
Trait Objects(动态分发)示例:
trait Draw {
fn draw(&self);
}
struct Circle;
struct Square;
impl Draw for Circle {
fn draw(&self) {
println!("画一个圆");
}
}
impl Draw for Square {
fn draw(&self) {
println!("画一个方形");
}
}
fn draw_shape(shape: &dyn Draw) {
shape.draw();
}
fn main() {
let c = Circle;
let s = Square;
draw_shape(&c);
draw_shape(&s);
}
泛型约束示例:
fn print_area<T: Draw>(shape: &T) {
shape.draw();
}
Unsafe Rust
有时需要绕过编译器的安全检查来做底层操作,这时用 unsafe 代码块。
fn main() {
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
}
注意: unsafe 代码需谨慎使用,避免产生悬空指针、数据竞争等问题。
生命周期(Lifetimes)深入
生命周期标注帮助编译器保证引用的有效性。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let string2 = "short";
let result = longest(string1.as_str(), string2);
println!("最长的字符串是 {}", result);
}
函数式编程风格
迭代器
迭代器让集合操作更简洁高效。
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let sum: i32 = numbers.iter()
.map(|x| x * 2)
.filter(|x| *x > 5)
.sum();
println!("结果是 {}", sum);
}
闭包
闭包是匿名函数,能捕获环境变量。
fn main() {
let add = |a, b| a + b;
println!("2 + 3 = {}", add(2, 3));
}
错误处理的高级技巧
自定义错误类型
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl MyError {
fn new(msg: &str) -> MyError {
MyError { details: msg.to_string() }
}
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.details)
}
}
impl std::error::Error for MyError {
fn description(&self) -> &str {
&self.details
}
}
fn do_something(flag: bool) -> Result<(), MyError> {
if flag {
Ok(())
} else {
Err(MyError::new("失败了"))
}
}
fn main() {
match do_something(false) {
Ok(_) => println!("成功"),
Err(e) => println!("错误: {}", e),
}
}
高级类型系统
关联类型
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
struct Counter {
count: u32,
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}
模块与包管理
- 使用 Cargo 管理依赖与构建
- 利用 Cargo workspace 管理多包项目
- 通过 mod 关键字定义模块,pub 控制可见性
// src/lib.rs
pub mod greetings;
// src/greetings.rs
pub fn hello() {
println!("Hello from module!");
}
FFI(与其他语言互操作)
示例:调用 C 语言函数
extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("绝对值: {}", abs(-3));
}
}
总结
Rust 是一门非常强大的编程语言,它通过独特的所有权和借用机制,结合编译时的错误检查,确保了内存安全和高效的性能。通过本教程,您应该已经掌握了 Rust 的基本语法、控制流、数据类型以及进阶实践中的一些常用模式。继续深入学习,您将能够更好地掌握 Rust 的高级特性,编写高效、安全的系统级应用程序。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。