Rust 完整指南:从安装到打包发布
引言Rust 是一门系统级编程语言由 Mozilla 研究院开发旨在提供内存安全、并发安全和高性能。它没有垃圾回收器而是通过所有权系统在编译时保证内存安全。Rust 的语法类似 C/C但融入了许多现代语言特性如模式匹配、类型推断、trait 系统等。近年来Rust 在开发者社区中越来越受欢迎被广泛应用于操作系统、嵌入式、WebAssembly、网络服务等领域。本指南将从零开始带你全面了解 Rust 的安装、语法、核心概念、工具链、项目组织一直到如何将你的 crate 发布到 crates.io。无论你是初学者还是有一定经验的开发者都能从中受益。安装 RustRust 官方提供了便捷的安装工具rustup它可以管理 Rust 版本和相关的工具链。我们将介绍在主流操作系统上的安装步骤。在 Windows 上安装访问 https://rustup.rs下载rustup-init.exe。运行下载的可执行文件会出现一个命令行界面提示选择安装选项。通常选择默认安装键入 1 并回车即可。安装程序会自动下载并安装 Rust 编译器rustc、包管理器 Cargo、以及文档等组件。安装完成后需要重启终端或手动刷新环境变量以便rustc和cargo命令可用。此外Rust 依赖于 Microsoft C 构建工具。如果你在安装后尝试编译代码时遇到链接错误可能需要安装 Visual Studio Build Tools 或 Visual Studio包含 C 工具链。在 macOS 上安装macOS 用户可以通过终端运行以下命令安装bashcurl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh该脚本会下载并运行rustup-init同样会有交互式选项选择默认安装即可。安装程序会自动将~/.cargo/bin添加到 PATH。之后你需要重启终端或执行source ~/.cargo/env使配置生效。在 Linux 上安装在 Linux 上同样使用上述curl命令进行安装。大多数 Linux 发行版需要安装编译器和链接器如gcc、make等。例如在 Ubuntu 上bashsudo apt update sudo apt install build-essential curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh安装完成后同样需要将~/.cargo/bin加入 PATH。验证安装安装完成后打开新终端并执行bashrustc --version cargo --version如果看到类似rustc 1.70.0 (90c541806 2023-05-31)的输出说明安装成功。更新和卸载 Rust更新 Rust 工具链bashrustup update卸载 Rustbashrustup self uninstall第一个 Rust 程序Hello, World!按照传统我们从 Hello, World! 开始。创建一个新目录比如hello_world并在其中新建一个文件main.rs内容如下rustfn main() { println!(Hello, world!); }在终端进入该目录执行bashrustc main.rs ./main # 在 Windows 上是 .\main.exe你会在屏幕上看到 Hello, world!。这里rustc直接编译了单个文件但在实际项目中我们通常使用 Cargo。使用 Cargo 创建项目Cargo 是 Rust 的构建系统和包管理器。创建一个新项目bashcargo new hello_cargo cd hello_cargoCargo 会生成如下目录结构texthello_cargo/ Cargo.toml src/ main.rsCargo.toml是项目的配置文件类似于package.json。src/main.rs是源代码文件。默认生成的main.rs已经包含一个 Hello, world! 程序。构建并运行bashcargo build # 编译生成可执行文件在 target/debug/hello_cargo cargo run # 编译并运行你也可以使用cargo check快速检查代码是否通过编译而不生成可执行文件。基础语法变量与可变性Rust 中变量默认是不可变的。使用let声明变量rustlet x 5; // 不可变 x 6; // 错误不能对不可变变量二次赋值若希望变量可变需添加mut关键字rustlet mut y 5; y 6; // 允许常量使用const声明必须注明类型且值必须在编译时确定rustconst MAX_POINTS: u32 100_000;变量可以隐藏shadowing即重新使用let声明同名变量新变量会覆盖旧变量rustlet x 5; let x x 1; // 新变量 x 为 6原 x 被隐藏数据类型Rust 是静态类型语言但编译器通常能推断类型。主要分为标量scalar和复合compound类型。标量类型整数有符号i8, i16, i32, i64, i128, isize与架构相关无符号u8, u16, u32, u64, u128, usize。默认i32。浮点数f32, f64。默认f64。布尔bool值为true或false。字符char用单引号Unicode 标量值如a、。复合类型元组不同类型值的集合长度固定。如let tup: (i32, f64, u8) (500, 6.4, 1);。可以通过模式匹配或索引访问tup.0。数组相同类型值的集合长度固定。如let arr [1, 2, 3];。访问arr[0]。数组存储在栈上若需要动态大小应使用 Vector。函数使用fn定义函数参数需注明类型返回值类型在箭头后注明rustfn add(x: i32, y: i32) - i32 { x y // 表达式不加分号即为返回值 }最后一个表达式就是返回值也可使用return提前返回。注释普通注释//或/* ... */文档注释///用于生成 API 文档支持 Markdown。控制流if 表达式rustlet number 3; if number 5 { println!(condition was true); } else if number 5 { println!(condition was five); } else { println!(condition was false); }if是表达式可以用于赋值rustlet condition true; let number if condition { 5 } else { 6 };循环loop无限循环可用break退出并可返回值。rustlet result loop { counter 1; if counter 10 { break counter * 2; } };while条件循环。for遍历集合最常用。rustlet a [10, 20, 30]; for element in a.iter() { println!(value: {}, element); } // 或使用范围 for number in 1..4 { println!({}, number); // 1 2 3 }所有权系统所有权是 Rust 最独特的特性它让 Rust 无需垃圾回收即可保证内存安全。所有权规则Rust 中每一个值都有一个被称为其所有者的变量。值在任一时刻有且只有一个所有者。当所有者变量离开作用域这个值将被丢弃。内存与分配对于栈上数据如标量拷贝是廉价的对于堆上数据如String当变量离开作用域时Rust 会自动调用drop释放内存。考虑以下代码rustlet s1 String::from(hello); let s2 s1; // s1 的所有权被移动到 s2s1 不再有效 println!({}, s1); // 错误s1 已被移动若想深拷贝堆数据可以使用clonerustlet s1 String::from(hello); let s2 s1.clone(); // 堆数据被复制 println!(s1 {}, s2 {}, s1, s2); // 都有效对于栈上数据如整数实现了Copytrait赋值时会自动拷贝rustlet x 5; let y x; // x 仍然有效因为整数是 Copy 的引用与借用如果我们想使用值但不获取所有权可以使用引用。引用默认也是不可变的。rustfn calculate_length(s: String) - usize { // s 是对 String 的引用 s.len() } let s1 String::from(hello); let len calculate_length(s1); // 传递引用s1 所有权未移动通过引用传递参数称为借用。引用默认不可变但可以创建可变引用rustfn change(s: mut String) { s.push_str(, world); } let mut s String::from(hello); change(mut s);注意在特定作用域中对特定数据只能有一个可变引用且不能同时拥有可变和不可变引用。这防止了数据竞争。切片切片是集合中一部分连续元素的引用它没有所有权。例如字符串切片rustlet s String::from(hello world); let hello s[0..5]; // hello let world s[6..11]; // world数组切片类似let slice arr[1..3];。字符串字面量本身就是切片let s: str Hello;。结构体与方法定义结构体使用struct关键字定义ruststruct User { username: String, email: String, sign_in_count: u64, active: bool, }实例化结构体rustlet user1 User { email: String::from(someoneexample.com), username: String::from(someusername123), active: true, sign_in_count: 1, };可以使用点号访问字段。如果变量名与字段名相同可以用字段初始化简写rustfn build_user(email: String, username: String) - User { User { email, username, active: true, sign_in_count: 1, } }结构体更新语法rustlet user2 User { email: String::from(anotherexample.com), ..user1 // 其余字段从 user1 获取注意 user1 的部分字段可能被移动 };元组结构体类似元组但有名ruststruct Color(i32, i32, i32); let black Color(0, 0, 0);单元结构体无字段ruststruct Empty;方法语法方法在impl块中定义第一个参数总是self或其变体self、mut self代表调用该方法的实例。rustimpl User { fn is_active(self) - bool { self.active } } let user1 User { ... }; println!({}, user1.is_active());关联函数在impl中定义不带self参数的函数称为关联函数通常用作构造函数例如String::from。rustimpl User { fn new(email: String, username: String) - User { User { email, username, active: true, sign_in_count: 1, } } } let user User::new(String::from(...), String::from(...));枚举与模式匹配枚举定义枚举允许你定义一个类型该类型的值只能是几个变体之一rustenum IpAddrKind { V4, V6, } let four IpAddrKind::V4;每个变体可以关联不同类型的数据rustenum IpAddr { V4(u8, u8, u8, u8), V6(String), } let home IpAddr::V4(127, 0, 0, 1); let loopback IpAddr::V6(String::from(::1));枚举也可以定义方法。Option 枚举Rust 没有空值而是使用OptionT枚举来表示值存在或不存在rustenum OptionT { Some(T), None, }它被包含在预导入模块中可以直接使用Some和None。rustlet some_number Some(5); let absent_number: Optioni32 None;使用OptionT时必须处理None的情况避免空指针异常。match 控制流match允许将一个值与一系列模式比较并执行匹配模式对应的代码。模式可以是字面值、变量名、通配符等。rustenum 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, } }匹配必须是穷尽的。如果不想处理所有情况可以使用_通配符rustlet some_u8_value 0u8; match some_u8_value { 1 println!(one), 3 println!(three), _ (), }if let 简洁控制当你只关心某一种模式而忽略其他时if let更简洁rustlet some_u8_value Some(0u8); if let Some(3) some_u8_value { println!(three); } else { // 可选 }模块系统Rust 提供了一套模块系统来组织代码包package、crate单元包、模块module和路径path。包、crate 与模块crate是一个二进制项或库。crate root是源代码文件Cargo 会依此编译。包是提供一系列功能的一个或多个 crate。包含一个Cargo.toml文件描述如何构建这些 crate。模块用于在 crate 内组织代码控制私有性。默认情况下所有项函数、结构体等都是私有的。使用pub关键字公开。路径路径有两种形式绝对路径从 crate root 开始使用 crate 名或字面量crate。相对路径从当前模块开始使用self、super或当前模块的标识符。例如在库 crate 中rustmod front_of_house { pub mod hosting { pub fn add_to_waitlist() {} } } pub fn eat_at_restaurant() { // 绝对路径 crate::front_of_house::hosting::add_to_waitlist(); // 相对路径 front_of_house::hosting::add_to_waitlist(); }use 关键字使用use将路径引入作用域类似于import。rustuse crate::front_of_house::hosting; // 或者使用相对路径 // use self::front_of_house::hosting; pub fn eat_at_restaurant() { hosting::add_to_waitlist(); }习惯上对于函数引入父模块对于结构体、枚举等引入完整路径。也可以使用as重命名。rustuse std::fmt::Result; use std::io::Result as IoResult;pub use可以重导出项使外部代码能访问原本私有的项。模块分割文件当模块变大时可以将它们放入单独的文件。在src/lib.rs或src/main.rs中rustmod front_of_house; // 告诉 Rust 从 front_of_house.rs 或 front_of_house/mod.rs 加载模块然后在src/front_of_house.rs中定义模块内容。如果模块还有子模块可以创建front_of_house目录和mod.rs。常用集合VectorVecT是动态数组可存储多个相同类型的值。rustlet mut v: Veci32 Vec::new(); v.push(5); v.push(6); // 使用 vec! 宏创建 let v vec![1, 2, 3]; // 读取元素 let third: i32 v[2]; // 索引越界 panic match v.get(2) { // 返回 OptionT Some(third) println!(third element is {}, third), None println!(no third element), } // 遍历 for i in v { println!({}, i); } for i in mut v { *i 50; // 解引用修改 }字符串Rust 的字符串是String可增长、可变、拥有所有权和str字符串切片。String内部使用 UTF-8 编码。rustlet mut s String::new(); let data initial contents; let s data.to_string(); // 或 initial contents.to_string() let s String::from(initial contents); // 更新 s.push_str(bar); // 追加字符串切片 s.push(l); // 追加字符 let s1 String::from(Hello, ); let s2 String::from(world!); let s3 s1 s2; // s1 被移动不能再使用 // 格式化宏 let s format!({}-{}, s1, s2); // 不支持索引访问因为 UTF-8 编码。需使用 chars() 或 bytes() for c in 你好.chars() { println!({}, c); // 你 好 } for b in 你好.bytes() { println!({}, b); // 输出字节 }HashMapHashMapK, V存储键值对。rustuse std::collections::HashMap; let mut scores HashMap::new(); scores.insert(String::from(Blue), 10); scores.insert(String::from(Yellow), 50); // 通过 collect 从元组向量创建 let teams vec![String::from(Blue), String::from(Yellow)]; let initial_scores vec![10, 50]; let scores: HashMap_, _ teams.iter().zip(initial_scores.iter()).collect(); // 访问 let score scores.get(Blue); // 返回 OptionV // 遍历 for (key, value) in scores { println!({}: {}, key, value); } // 更新insert 会覆盖entry 处理不存在时插入 scores.entry(String::from(Blue)).or_insert(50); // 仅当不存在时插入错误处理Rust 将错误分为两类可恢复错误如文件未找到和不可恢复错误如数组越界。panic! 不可恢复错误当程序遇到无法处理的错误时可以调用panic!宏程序会打印错误信息、展开并清理栈或直接中止。rustpanic!(crash and burn);可以通过设置环境变量RUST_BACKTRACE1获取回溯信息。Result 可恢复错误Result枚举定义如下rustenum ResultT, E { Ok(T), Err(E), }常用于可能失败的操作rustuse std::fs::File; use std::io::ErrorKind; let f File::open(hello.txt); let f match f { Ok(file) file, Err(error) match error.kind() { ErrorKind::NotFound match File::create(hello.txt) { Ok(fc) fc, Err(e) panic!(Problem creating the file: {:?}, e), }, other_error panic!(Problem opening the file: {:?}, other_error), }, };传播错误将错误返回给调用者处理rustuse std::io; use std::io::Read; use std::fs::File; fn read_username_from_file() - ResultString, io::Error { let f File::open(hello.txt); let mut f match f { Ok(file) file, Err(e) return Err(e), }; let mut s String::new(); match f.read_to_string(mut s) { Ok(_) Ok(s), Err(e) Err(e), } }使用?运算符简化rustfn read_username_from_file() - ResultString, io::Error { let mut f File::open(hello.txt)?; let mut s String::new(); f.read_to_string(mut s)?; Ok(s) }?会从Result中取出值若为Err则提前返回。也可链式调用rustfn read_username_from_file() - ResultString, io::Error { let mut s String::new(); File::open(hello.txt)?.read_to_string(mut s)?; Ok(s) }?还可以用于Option类型若为None则提前返回None。何时使用 panic在示例、原型代码和测试中可以使用panic!。在能确保不会出现Err的情况下也可以使用unwrap或expect。对于库代码应该将错误返回给调用者。泛型、trait 与生命周期泛型函数和结构体泛型允许定义适用于多种类型的函数或结构体rustfn largestT: PartialOrd Copy(list: [T]) - T { let mut largest list[0]; for item in list { if item largest { largest item; } } largest } struct PointT { x: T, y: T, } implT PointT { fn x(self) - T { self.x } }trait 定义与实现trait 类似于接口定义共享行为rustpub trait Summary { fn summarize(self) - String; } 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) } }trait 作为参数可以接受实现了某个 trait 的类型rustpub fn notify(item: impl Summary) { println!(Breaking news! {}, item.summarize()); }等价于 trait bound 语法rustpub fn notifyT: Summary(item: T) { println!(Breaking news! {}, item.summarize()); }多个 trait 使用rustpub fn notify(item: (impl Summary Display)) {}复杂 bound 可使用where子句rustfn some_functionT, U(t: T, u: U) - i32 where T: Display Clone, U: Clone Debug, { // ... }trait 也可以作为返回类型但只能返回单一类型rustfn returns_summarizable() - impl Summary { NewsArticle { ... } }生命周期注解生命周期确保引用始终有效。它们也是泛型的一种。rustfn longesta(x: a str, y: a str) - a str { if x.len() y.len() { x } else { y } }这里a是生命周期参数表示返回的引用与两个参数中的较小生命周期一致。结构体中也可包含引用需要生命周期注解ruststruct Excerpta { part: a str, }生命周期省略规则在某些情况下Rust 编译器可以自动推断生命周期这称为生命周期省略规则。例如每个引用参数都有自己的生命周期参数。如果只有一个输入生命周期它会被赋给所有输出生命周期。如果有多个输入生命周期但其中一个为self或mut self则self的生命周期赋给所有输出。编写测试测试函数在 Rust 中测试是通过#[test]属性标记的函数。运行cargo test会执行所有测试函数。rust#[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 2, 4); } #[test] fn another() { panic!(Make this test fail); } }断言assert!(expression)若表达式为 false 则 panic。assert_eq!(left, right)和assert_ne!(left, right)比较两个值若不等/等则 panic。可添加自定义消息assert_eq!(a, b, a 不等于 b, a{}, b{}, a, b)测试组织单元测试通常放在与代码相同的文件中使用#[cfg(test)]条件编译。集成测试放在tests目录下每个文件被视为单独的 crate只能测试公共 API。智能指针智能指针是实现了Deref和Droptrait 的数据结构它们拥有数据的所有权并提供额外功能。BoxTBoxT用于在堆上分配值最简单直接。适合递归类型、在需要特定大小的地方使用。rustlet b Box::new(5); println!(b {}, b); // 可以像普通引用一样使用 // 递归类型 Cons list enum List { Cons(i32, BoxList), Nil, }Deref 和 Drop traitDeref允许智能指针像普通引用一样解引用*v。Rust 会自动解引用以匹配类型。Drop允许自定义值离开作用域时的清理代码。RcT、RefCellT 和内部可变性RcT是引用计数指针允许多个所有者只读。RefCellT在运行时检查借用规则实现内部可变性即即使RefCellT本身不可变也能修改其内部值。rustuse std::rc::Rc; use std::cell::RefCell; let value Rc::new(RefCell::new(5)); let a Rc::clone(value); let b Rc::clone(value); *value.borrow_mut() 10; // 修改内部值 println!({:?}, value); // RefCell { value: 15 }循环引用RcT和RefCellT可能导致循环引用和内存泄漏。可以使用WeakT打破循环。并发编程线程使用thread::spawn创建新线程rustuse std::thread; use std::time::Duration; let handle thread::spawn(|| { for i in 1..10 { println!(hi number {} from the spawned thread!, i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!(hi number {} from the main thread!, i); thread::sleep(Duration::from_millis(1)); } handle.join().unwrap(); // 等待子线程结束消息传递使用通道channel在线程间通信rustuse std::sync::mpsc; use std::thread; let (tx, rx) mpsc::channel(); thread::spawn(move || { let val String::from(hi); tx.send(val).unwrap(); }); let received rx.recv().unwrap(); // 阻塞接收 println!(Got: {}, received);共享状态使用互斥器MutexT和原子引用计数ArcT实现线程间共享数据rustuse std::sync::{Arc, Mutex}; use std::thread; 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!(Result: {}, *counter.lock().unwrap());Send 和 Sync traitSend允许在线程间转移所有权。几乎所有 Rust 类型都是Send但RcT不是。Sync允许多线程同时访问。实现了Sync的类型其引用T是Send。基本类型都是Sync但RefCellT不是MutexT是。面向对象特性trait 对象trait 对象允许动态分发实现类似多态的效果。需要使用dyn关键字。rustpub trait Draw { fn draw(self); } pub struct Screen { pub components: VecBoxdyn Draw, } impl Screen { pub fn run(self) { for component in self.components.iter() { component.draw(); } } }这里Boxdyn Draw是一个 trait 对象它可以指向任何实现了Draw的类型。实现多态可以为不同类型实现同一个 trait然后通过 trait 对象统一调用ruststruct Button { width: u32, height: u32, label: String, } impl Draw for Button { fn draw(self) { // 绘制按钮 } } struct SelectBox { width: u32, height: u32, options: VecString, } impl Draw for SelectBox { fn draw(self) { // 绘制选择框 } } fn main() { let screen Screen { components: vec![ Box::new(SelectBox { ... }), Box::new(Button { ... }), ], }; screen.run(); }模式与匹配进阶模式语法模式可以出现在match、if let、while let、for循环、let语句、函数参数等位置。常见模式字面值1、abc变量名x会绑定值通配符_范围..1..5解构结构体、元组、枚举引用模式v、ref v、ref mut v匹配守卫在模式后添加if条件示例rustlet x 5; match x { 1 println!(one), 2 | 3 | 5 println!(two, three or five), 6..10 println!(six to ten), _ println!(something else), } let p Point { x: 0, y: 7 }; match p { Point { x, y: 0 } println!(on the x axis at {}, x), Point { x: 0, y } println!(on the y axis at {}, y), Point { x, y } println!(on neither axis: ({}, {}), x, y), }高级特性不安全 Rust不安全 Rust 允许你进行一些编译器无法保证安全的操作如解引用裸指针、调用不安全函数、访问可变静态变量、实现不安全 trait。使用unsafe关键字标记代码块或函数。rustunsafe fn dangerous() {} let mut num 5; let r1 num as *const i32; // 裸指针 unsafe { dangerous(); println!(r1 is: {}, *r1); // 解引用裸指针 }应尽量将不安全代码封装在安全抽象中。高级 trait关联类型在 trait 中指定一个类型占位符。rustpub trait Iterator { type Item; fn next(mut self) - OptionSelf::Item; }默认泛型参数和运算符重载std::ops中的 trait 如Add支持重载。完全限定语法当多个 trait 有同名方法时使用Type as Trait::method(...)。高级类型类型别名type Kilometers i32;动态大小类型和Sizedtrait如str是动态大小只能通过str使用。泛型默认是Sized可以用?Sized放宽。宏宏分为声明宏和过程宏。声明宏使用macro_rules!定义类似于模式匹配生成代码。过程宏接收代码作为输入操作后输出代码有三种自定义#[derive]宏、类属性宏、类函数宏。示例声明宏rustmacro_rules! say_hello { () { println!(Hello!); }; } say_hello!();异步编程Rust 的异步编程基于Futuretrait 和async/.await语法。async/.await使用async fn定义异步函数返回一个实现了Future的类型。在 async 函数内部可以使用.await等待另一个 Future 完成。rustasync fn hello() { println!(Hello, async!); } #[tokio::main] async fn main() { hello().await; }FuturesFuture代表一个可能尚未完成的计算。Rust 的 Future 是惰性的只有被轮询才会推进。通常需要一个执行器executor来驱动 Future。异步运行时常用的异步运行时是 Tokio 和 async-std。它们提供了 I/O、计时器、任务生成等功能。使用 Tokiorustuse tokio::time; #[tokio::main] async fn main() { let handle tokio::spawn(async { time::sleep(time::Duration::from_secs(1)).await; println!(task finished); }); handle.await.unwrap(); }项目结构与工作空间工作空间工作空间是一系列共享同一个 Cargo.lock 和输出目录的包。在根目录创建Cargo.tomltoml[workspace] members [ adder, add-one, ]每个成员都是一个独立的 crate。成员之间可以通过路径依赖。依赖管理Cargo.toml在Cargo.toml的[dependencies]部分添加依赖toml[dependencies] rand 0.8.5Cargo 会从 crates.io 下载相应版本。版本指定版本号遵循语义化版本。可以使用^、~、*、、等指定范围。例如rand 0.8相当于^0.8允许兼容 0.8.x 但不包括 0.9.0。依赖覆盖可以使用[patch]或[replace]覆盖依赖来源例如使用本地路径或 git 仓库。构建脚本与自定义构建如果需要在编译前执行一些代码如生成代码、链接系统库可以在项目根目录创建build.rs构建脚本。它会在编译 crate 前被编译并执行。rust// build.rs fn main() { println!(cargo:rustc-link-searchnative/usr/local/lib); }构建脚本可以通过println!输出指令给 Cargo。文档编写文档注释文档注释使用///或//!。支持 Markdown并会生成 HTML 文档。rust/// Adds one to the number given. /// /// # Examples /// /// /// let arg 5; /// let answer my_crate::add_one(arg); /// assert_eq!(6, answer); /// pub fn add_one(x: i32) - i32 { x 1 }# Examples部分的代码会作为测试运行。生成文档运行cargo doc会在target/doc生成文档。cargo doc --open会在浏览器打开。发布到 crates.io创建账号访问 crates.io使用 GitHub 账号登录然后在本地使用cargo login API_TOKEN登录。打包在发布前确保Cargo.toml中有必要的元数据toml[package] name my_crate version 0.1.0 authors [Your Name youexample.com] edition 2021 description A short description of my crate license MIT OR Apache-2.0 repository https://github.com/yourname/my_crate运行cargo publish --dry-run检查。然后执行cargo publish发布。发布与版本管理发布后无法删除但可以发布新版本。修改版本号后再运行cargo publish。FFI 与外部语言接口调用 C 函数使用extern块声明外部函数并链接到相应库。rustextern C { fn abs(input: i32) - i32; } fn main() { unsafe { println!(Absolute value of -3 according to C: {}, abs(-3)); } }需要在构建脚本或通过links键指定库。从 C 调用 Rust将 Rust 函数标记为#[no_mangle]并使用extern C导出编译为静态库或动态库。rust#[no_mangle] pub extern C fn call_from_c() { println!(Just called a Rust function from C!); }在Cargo.toml中设置 crate 类型toml[lib] crate-type [staticlib, cdylib]C 代码可以链接生成的库并调用函数。常用开发工具rustfmt 和 clippyrustfmt自动格式化代码cargo fmtclippy提供更多 lint 检查cargo clippyrust-analyzerrust-analyzer 是 Rust 的语言服务器提供代码补全、跳转定义等功能。主流编辑器VS Code、Vim/Neovim、Emacs都支持。生态与常用库Rust 拥有丰富且活跃的生态系统。以下是一些常用库Web 框架Actix-web、Rocket、Warp异步运行时Tokio、async-std序列化serde与 JSON、YAML、TOML 等配合HTTP 客户端reqwest数据库驱动sqlx异步、dieselORM日志log、env_logger命令行解析clap错误处理anyhow、thiserror测试proptest、quickcheck嵌入式embedded-halWebAssemblywasm-bindgen