摘要: 本文简要介绍了Rust语言的发展历史,通过文字和源代码形式介绍Rust语言基本语法、开发工具、所有权模型、并发编程等。 本文作为Rust语言的入门资料,读者可以通过本文快速了解Rust语言的基本用法。
Rust 是一门系统编程语言,专注于安全、并发和性能。它由 Mozilla 研究员 Graydon Hoare 于 2006 年作为个人项目开始开发。
Rust 的设计目标是提供内存安全、并发安全和高性能:
内存安全:
零成本抽象:
并发安全:
实用性:
Rust 被广泛应用于:

Rust 的吉祥物是一只名为 Ferris 的螃蟹。
参考:
rustup 是 Rust 的官方安装器和版本管理工具。
Mac/Linux 安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 配置环境变量(安装程序会自动添加到 shell 配置文件)
source $HOME/.cargo/env
Windows 安装:
winget install Rustlang.Rustup验证安装:
rustc --version
# rustc 1.75.0 (82e1608df 2023-12-21)
cargo --version
# cargo 1.75.0 (1d8b05cdd 2023-11-20)
# 更新 Rust
rustup update
# 查看已安装的工具链
rustup show
# 卸载 Rust
rustup self uninstall
创建或编辑 ~/.cargo/config 文件:
mkdir -p ~/.cargo
cat > ~/.cargo/config << 'EOF'
[source.crates-io]
replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
EOF
或使用字节跳动的镜像:
[source.crates-io]
replace-with = 'rsproxy'
[source.rsproxy]
registry = "https://rsproxy.cn/crates.io-index"
Rust 工具链包含:
安装额外工具:
# 安装 rustfmt 和 clippy
rustup component add rustfmt clippy
# 安装 rust-analyzer
rustup component add rust-analyzer
创建新项目:
cargo new hello_world
cd hello_world
项目结构:
hello_world/
├── Cargo.toml # 项目配置文件
└── src/
└── main.rs # 源代码
src/main.rs:
fn main() {
println!("Hello, world!");
}
编译并运行:
# 编译并运行
cargo run
# Hello, world!
# 只编译
cargo build
# 编译生成的二进制文件在 target/debug/hello_world
# 发布版本编译(开启优化)
cargo build --release
# 生成文件在 target/release/hello_world
# 检查代码是否能编译(不生成可执行文件,速度更快)
cargo check
直接使用 rustc 编译:
# 创建单文件
echo 'fn main() { println!("Hello, world!"); }' > hello.rs
# 编译
rustc hello.rs
# 运行
./hello
# Hello, world!
Rust 有 53 个关键字,分为严格关键字和保留关键字。
严格关键字(已被使用):
as break const continue crate
else enum extern false fn
for if impl in let
loop match mod move mut
pub ref return self Self
static struct super trait true
type unsafe use where while
async await dyn
保留关键字(保留供未来使用):
abstract become box do final
macro override priv try typeof
unsized virtual yield
原始标识符: 如果需要使用关键字作为标识符,可以使用 r# 前缀:
let r#match = "match"; // 使用 match 关键字作为变量名
整数类型:
| 长度 | 有符号 | 无符号 |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| 128-bit | i128 | u128 |
| arch | isize | usize |
let x: i32 = 42;
let y: u64 = 100;
let z = 98_222; // 使用下划线分隔,提高可读性
let hex = 0xff; // 十六进制
let octal = 0o77; // 八进制
let binary = 0b1111_0000; // 二进制
let byte = b'A'; // 字节(仅限 u8)
浮点类型:
let x: f32 = 2.0; // f32
let y: f64 = 3.0; // f64(默认类型)
布尔类型:
let t: bool = true;
let f: bool = false;
字符类型:
let c: char = 'z';
let emoji: char = '😻'; // char 是 4 字节 Unicode 标量值
元组 (Tuple):
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解构
let (x, y, z) = tup;
println!("y = {}", y);
// 索引访问
let five_hundred = tup.0;
let six_point_four = tup.1;
数组 (Array):
let a: [i32; 5] = [1, 2, 3, 4, 5]; // 固定长度
let first = a[0];
let second = a[1];
// 初始化相同值
let a = [3; 5]; // [3, 3, 3, 3, 3]
切片 (Slice):
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // [2, 3]
fn main() {
// 不可变变量(默认)
let x = 5;
// x = 6; // 错误!不能修改不可变变量
// 可变变量
let mut y = 5;
println!("y = {}", y);
y = 6;
println!("y = {}", y);
// 常量(必须标注类型,使用大写字母和下划线)
const MAX_POINTS: u32 = 100_000;
}
let x = 5;
let x = x + 1; // 遮蔽前一个 x
let x = x * 2; // 再次遮蔽
println!("x = {}", x); // 12
// 可以改变类型
let spaces = " ";
let spaces = spaces.len(); // 从 &str 变为 usize
let guess = "42".parse().expect("Not a number!"); // 错误!无法推断类型
let guess: i32 = "42".parse().expect("Not a number!"); // 正确
// 使用 turbofish 语法
let guess = "42".parse::<i32>().expect("Not a number!");
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 {
println!("again!");
break; // 退出循环
}
// 从循环返回值
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 返回值
}
};
println!("结果:{}", result); // 20
// 循环标签
'outer: loop {
loop {
break 'outer; // 跳出外层循环
}
}
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
// 遍历数组
let a = [10, 20, 30, 40, 50];
for element in a {
println!("值:{}", element);
}
// Range
for number in 1..4 { // 不包含 4
println!("{}", number);
}
for number in 1..=4 { // 包含 4
println!("{}", number);
}
// 倒序
for number in (1..4).rev() {
println!("{}", number);
}
// 带索引
for (index, value) in a.iter().enumerate() {
println!("索引 {} 的值是 {}", index, value);
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// 带绑定的模式
match some_value {
Some(x) => println!("值:{}", x),
None => println!("没有值"),
}
// 通配符
let dice_roll = 9;
match dice_roll {
3 => println!("特殊值 3"),
7 => println!("特殊值 7"),
_ => println!("其他值"), // _ 匹配所有其他情况
}
let some_value = Some(3);
// 使用 match
match some_value {
Some(3) => println!("three"),
_ => (),
}
// 使用 if let
if let Some(3) = some_value {
println!("three");
}
所有权是 Rust 最独特的特性,使得 Rust 无需垃圾回收器即可保证内存安全。
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权移动到 s2
// println!("{}", s1); // 错误!s1 已失效
println!("{}", s2); // 正确
let s1 = String::from("hello");
let s2 = s1.clone(); // 深拷贝
println!("s1 = {}, s2 = {}", s1, s2); // 都有效
栈上的简单类型实现了 Copy trait,赋值时会自动复制:
let x = 5;
let y = x; // x 被复制
println!("x = {}, y = {}", x, y); // 都有效
实现 Copy 的类型:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 借用
println!("'{}' 的长度是 {}", s1, len); // s1 仍然有效
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s 离开作用域,但因为它没有所有权,所以不会释放
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // hello, world
}
fn change(s: &mut String) {
s.push_str(", world");
}
可变引用的限制:
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
// let r3 = &mut s; // 错误!不能同时有不可变和可变引用
println!("{} and {}", r1, r2);
// r1 和 r2 的作用域到此结束
let r3 = &mut s; // 现在没问题
Rust 编译器保证引用永远不会成为悬垂引用:
fn dangle() -> &String { // 错误!
let s = String::from("hello");
&s // 返回 s 的引用
} // s 离开作用域并被丢弃,其内存被释放
// 正确做法:返回所有权
fn no_dangle() -> String {
let s = String::from("hello");
s // 返回 s,所有权被移出
}
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("anotheremail@example.com");
}
fn build_user(email: String, username: String) -> User {
User {
email, // 简写
username, // 简写
active: true,
sign_in_count: 1,
}
}
let user2 = User {
email: String::from("another@example.com"),
..user1 // 其余字段使用 user1 的值
};
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 方法
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// 关联函数(类似静态方法)
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!("面积:{}", rect1.area());
let sq = Rectangle::square(3);
}
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
enum Option<T> {
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// 方法体
}
}
let m = Message::Write(String::from("hello"));
m.call();
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("最大值:{}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("最大值:{}", result);
}
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 只为特定类型实现方法
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
enum Result<T, E> {
Ok(T),
Err(E),
}
Trait 类似于其他语言中的接口。
pub trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn summarize_author(&self) -> String {
String::from("(Read more...)")
}
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// Trait Bound 语法
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// 多个 Trait Bound
pub fn notify<T: Summary + Display>(item: &T) {
// ...
}
// where 子句
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
// Debug - 格式化打印
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
// Clone - 克隆
#[derive(Clone)]
struct MyStruct;
// Copy - 复制
#[derive(Copy, Clone)]
struct MySmallStruct;
// PartialEq, Eq - 相等比较
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
fn main() {
panic!("crash and burn");
}
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("打开文件出错:{:?}", error),
};
}
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// 链式调用
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
let f = File::open("hello.txt").unwrap();
let f = File::open("hello.txt")
.expect("无法打开 hello.txt");
// 创建 vector
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
// 添加元素
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
// 读取元素
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("第三个元素:{}", third);
match v.get(2) {
Some(third) => println!("第三个元素:{}", third),
None => println!("没有第三个元素"),
}
// 遍历
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
// 可变遍历
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
// 创建字符串
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");
// 更新字符串
let mut s = String::from("foo");
s.push_str("bar");
s.push('l');
// 拼接
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1 被移动了,不能再使用
// format! 宏
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
// 遍历字符串
for c in "नमस्ते".chars() {
println!("{}", c);
}
for b in "नमस्ते".bytes() {
println!("{}", b);
}
use std::collections::HashMap;
// 创建
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// 访问
let team_name = String::from("Blue");
let score = scores.get(&team_name);
match score {
Some(s) => println!("分数:{}", s),
None => println!("队伍不存在"),
}
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
// 只在键不存在时插入
scores.entry(String::from("Blue")).or_insert(50);
// 根据旧值更新
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("子线程:{}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("主线程:{}", i);
thread::sleep(Duration::from_millis(1));
}
}
use std::thread;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("子线程:{}", i);
}
});
for i in 1..5 {
println!("主线程:{}", i);
}
handle.join().unwrap(); // 等待子线程结束
}
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("vector: {:?}", v);
});
handle.join().unwrap();
}
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("收到:{}", received);
}
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果:{}", *counter.lock().unwrap());
}
// src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
pub fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
}
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
// 使用 as 重命名
use std::io::Result as IoResult;
// 导出名称
pub use crate::front_of_house::hosting;
src/
├── main.rs
├── lib.rs
└── front_of_house/
├── mod.rs
└── hosting.rs
src/lib.rs:
mod front_of_house;
pub use crate::front_of_house::hosting;
src/front_of_house/mod.rs:
pub mod hosting;
src/front_of_house/hosting.rs:
pub fn add_to_waitlist() {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
#[test]
#[should_panic]
fn another() {
panic!("Make this test fail");
}
#[test]
fn it_works_with_result() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
}
运行测试:
cargo test
# 运行特定测试
cargo test test_name
# 显示输出
cargo test -- --show-output
# 并行或串行
cargo test -- --test-threads=1
tests/integration_test.rs:
use my_crate;
#[test]
fn it_adds_two() {
assert_eq!(4, my_crate::add_two(2));
}
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
[dependencies]
serde = "1.0"
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
[dev-dependencies]
criterion = "0.5"
[profile.release]
opt-level = 3
# 创建新项目
cargo new project_name
cargo new --lib lib_name
# 构建
cargo build
cargo build --release
# 运行
cargo run
cargo run --release
# 检查
cargo check
# 测试
cargo test
# 文档
cargo doc --open
# 更新依赖
cargo update
# 清理
cargo clean
# 格式化
cargo fmt
# 代码检查
cargo clippy
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
// 递归类型
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
use std::rc::Rc;
enum List {
Cons(i32, Rc<List>),
Nil,
}
use List::{Cons, Nil};
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}
use std::cell::RefCell;
fn main() {
let x = RefCell::new(5);
*x.borrow_mut() += 1;
println!("x = {:?}", x);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
let i = ImportantExcerpt {
part: first_sentence,
};
}
let s: &'static str = "I have a static lifetime.";
use tokio;
#[tokio::main]
async fn main() {
let result = fetch_data().await;
println!("结果:{}", result);
}
async fn fetch_data() -> String {
// 模拟异步操作
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
String::from("Data")
}
use tokio;
#[tokio::main]
async fn main() {
let task1 = tokio::spawn(async {
// 任务 1
1
});
let task2 = tokio::spawn(async {
// 任务 2
2
});
let result1 = task1.await.unwrap();
let result2 = task2.await.unwrap();
println!("结果:{} + {} = {}", result1, result2, result1 + result2);
}
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
use proc_macro;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// 实现
}
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci(n-1) + fibonacci(n-2),
}
}
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
[profile.release]
opt-level = 3 # 最大优化
lto = true # 链接时优化
codegen-units = 1 # 减少代码生成单元
strip = true # 移除符号表
Result 和 Option 而不是 panic!? 运算符传播错误std::error::Error trait/// 计算两个数的和
///
/// # Examples
///
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
cargo clippy
| 特性 | Rust | C++ | Go | Python |
|---|---|---|---|---|
| 内存安全 | 编译时保证 | 手动管理 | GC | GC |
| 性能 | 极高 | 极高 | 高 | 低 |
| 学习曲线 | 陡峭 | 陡峭 | 平缓 | 平缓 |
| 并发模型 | 所有权+类型系统 | 线程+锁 | Goroutine | GIL限制 |
| 包管理 | Cargo | 多种 | go modules | pip |
| 编译速度 | 较慢 | 慢 | 快 | 解释执行 |