Rust返回值、错误处理、包和模块和格式化输出
目录
- 认识生命周期
- 返回值与错误处理
- panic深入剖析
- 可恢复的错误Result
- 包和模块
- 包Crate
- 模块Module
- 使用use及受限可见性
- 注释和文档
- 格式化输出
认识生命周期
什么是生命周期?
- 定义:生命周期是 Rust 中用来管理引用的有效范围的概念。
- 作用:确保引用不会超出被引用的数据的有效范围,避免悬空指针问题。
生命周期注解
- 语法:使用 'a 形式的生命周期注解。
// 定义一个带有生命周期注解的函数
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("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("The longest string is {}", result);
}
多个生命周期
多个生命周期注解:当函数或结构体涉及多个引用时,需要明确指定每个引用的生命周期。
// 定义一个带有多个生命周期注解的函数
fn longest_with_an_announcement<'a, 'b>(x: &'a str, y: &'a str, ann: &'b str) -> &'a str {
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("hello");
let string2 = String::from("world");
let result = longest_with_an_announcement(string1.as_str(), string2.as_str(), "Drum roll please");
println!("The longest string is {}", result);
}
返回值与错误处理
错误处理概述
- 不可恢复的错误:通常使用 panic! 宏处理。
- 可恢复的错误:通常使用 Result 枚举处理。
panic! 深入剖析
panic! 宏
- 定义:panic! 宏用于触发程序崩溃,并打印一条错误消息。
- 用途:用于处理无法恢复的严重错误。
fn divide_by_zero() {
panic!("Attempted to divide by zero");
}
fn main() {
divide_by_zero();
}
panic! 的工作机制
- 堆栈回溯:当 panic! 触发时,Rust 会打印堆栈回溯信息,帮助调试。
- 资源清理:Rust 会在 panic! 发生时尝试清理资源,以防止内存泄漏。
fn main() {
let v = vec![1, 2, 3];
// 尝试访问越界的元素
let result = v.get(5).expect("Index out of bounds");
println!("Result: {:?}", result);
}
可恢复的错误 Result
Result 枚举
- 定义:Result 枚举有两种变体:Ok(T) 和 Err(E)。
- 用途:用于处理可以恢复的错误。
Result 的使用
- 创建 Result:使用 Ok 和 Err 构造函数。
- 匹配 Result:使用模式匹配或 match 表达式。
fn divide(a: isize, b: isize) -> Result<isize, &'static str> {
if b == 0 {
Err("Cannot divide by zero")
} else {
Ok(a / b)
}
}
fn main() {
let result = divide(10, 2);
match result {
Ok(value) => println!("Result: {}", value),
Err(e) => println!("Error: {}", e),
}
}
unwrap 和 expect
unwrap
:用于从 Result 中提取值,如果结果是 Err,则触发 panic!。expect
:与 unwrap 类似,但可以提供自定义的错误消息。
fn main() {
let result = divide(10, 0);
let value = result.unwrap_or_else(|e| {
println!("Error: {}", e);
0
});
println!("Result: {}", value);
}
map 和 and_then
map
:用于在 Ok 值上应用函数。and_then
:用于在 Ok 值上应用另一个 Result 函数。
fn square(x: isize) -> isize {
x * x
}
fn main() {
let result = divide(10, 2);
let squared_result = result.map(square);
match squared_result {
Ok(value) => println!("Squared result: {}", value),
Err(e) => println!("Error: {}", e),
}
}
? 操作符
- ? 操作符:用于从函数返回 Result,并自动处理 Err 情况。
fn divide(a: isize, b: isize) -> Result<isize, &'static str> {
if b == 0 {
Err("Cannot divide by zero")
} else {
Ok(a / b)
}
}
fn calculate(a: isize, b: isize) -> Result<isize, &'static str> {
let result = divide(a, b)?;
Ok(result * 2)
}
fn main() {
match calculate(10, 2) {
Ok(value) => println!("Result: {}", value),
Err(e) => println!("Error: {}", e),
}
}
包和模块
包(Crate)
什么是包(Crate)
- 定义:在 Rust 中,一个 crate 是一个编译单元,它可以是一个库(library)或者一个可执行程序(executable)。
- 文件结构:一个 crate 通常包含一个
Cargo.toml
文件和一个入口文件(如src/main.rs
或src/lib.rs
)。
创建一个简单的 crate
cargo new my_crate --bin
cd my_crate
Cargo.toml 文件
[package]
name = "my_crate"
version = "0.1.0"
authors = ["Your Name <your.email@example.com>"]
edition = "2018"
[dependencies]
入口文件
// src/main.rs
fn main() {
println!("Hello, world!");
}
模块(Module)
什么是模块(Module)
- 定义:模块是 Rust 中组织代码的基本单位,可以包含其他模块和项(如函数、结构体、枚举等)。
- 语法:使用 mod 关键字定义模块。
创建模块
// src/main.rs
mod greeting;
fn main() {
greeting::say_hello();
}
// src/greeting.rs
pub fn say_hello() {
println!("Hello, world!");
}
模块路径
- 相对路径:使用
mod
关键字定义模块时,可以使用相对路径。 - 绝对路径:从
crate
根目录开始的路径。
// src/main.rs
mod greeting;
fn main() {
greeting::say_hello();
}
// src/greeting.rs
pub fn say_hello() {
println!("Hello, world!");
}
使用 use 关键字
引入模块
- 引入模块:使用 use 关键字引入模块中的项。
// src/main.rs
mod greeting;
use greeting::say_hello;
fn main() {
say_hello();
}
// src/greeting.rs
pub fn say_hello() {
println!("Hello, world!");
}
别名
- 别名:可以为引入的项定义别名。
// src/main.rs
mod greeting;
use greeting::say_hello as greet;
fn main() {
greet();
}
// src/greeting.rs
pub fn say_hello() {
println!("Hello, world!");
}
受限可见性
可见性修饰符
- 私有(private):默认情况下,所有项都是私有的。
- 公共(public):使用 pub 关键字声明公共项。
// src/main.rs
mod greeting;
use greeting::say_hello;
fn main() {
say_hello();
}
// src/greeting.rs
pub fn say_hello() {
println!("Hello, world!");
}
可见性层次
- 模块层次:可以控制整个模块的可见性。
- 项层次:可以控制单个项的可见性。
// src/main.rs
mod greeting;
use greeting::say_hello;
fn main() {
say_hello();
}
// src/greeting.rs
pub mod greeting {
pub fn say_hello() {
println!("Hello, world!");
}
}
注释和文档
文档注释
- 文档注释:使用
///
或/*!
开头的注释。
// src/main.rs
mod greeting;
use greeting::say_hello;
fn main() {
say_hello();
}
// src/greeting.rs
/// Prints a greeting message.
pub fn say_hello() {
println!("Hello, world!");
}
自动生成文档
cargo doc
:可以生成文档。
cargo doc --open
格式化输出
format! 宏
格式化字符串:使用 format!
宏生成格式化的字符串。
fn main() {
let name = "Alice";
let age = 30;
let message = format!("Hello, my name is {} and I am {} years old.", name, age);
println!("{}", message);
}
writeln! 宏
- 格式化输出到标准输出:使用
writeln!
宏输出格式化的字符串。
fn main() {
let name = "Alice";
let age = 30;
writeln!(std::io::stdout(), "Hello, my name is {} and I am {} years old.", name, age).unwrap();
}
printf! 宏
- 格式化输出到标准输出:使用
printf!
宏输出格式化的字符串。
fn main() {
let name = "Alice";
let age = 30;
printf!("Hello, my name is %s and I am %d years old.\n", name, age);
}
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。