目录全局变量错误处理unsafeRustmacro宏编程asnyc/await异步编程全局变量全局变量是在整个程序范围内可见的变量。虽然Rust强调模块化和封装,但在某些情况下,全局变量仍然有其用途。定义全局变量//定义全局变量staticCOUNTER:u32
全局变量是在整个程序范围内可见的变量。虽然 Rust 强调模块化和封装,但在某些情况下,全局变量仍然有其用途。
定义全局变量
// 定义全局变量
static COUNTER: u32 = 0;
fn increment_counter() {
COUNTER += 1;
}
fn main() {
increment_counter();
println!("Counter: {}", COUNTER);
}
可变全局变量
在 Rust 中,默认情况下全局变量是不可变的。如果需要可变全局变量,可以使用 static mut
关键字。
// 定义可变全局变量
static mut COUNTER: u32 = 0;
fn increment_counter() {
unsafe {
COUNTER += 1;
}
}
fn main() {
increment_counter();
println!("Counter: {}", COUNTER);
}
Rust 提供了多种错误处理机制,包括:
Result 类型是 Rust 中最常用的错误处理类型,它表示一个可能出错的操作。Result 类型有两种变体:Ok(T) 和 Err(E)。
使用 Result
use std::fs::File;
use std::io::{self, Read};
fn read_file(filename: &str) -> io::Result<String> {
let mut file = File::open(filename)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
match read_file("example.txt") {
Ok(contents) => println!("File contents: {}", contents),
Err(e) => eprintln!("Error reading file: {}", e),
}
}
使用 ? 操作符
?
操作符用于将 Result
类型的错误向上抛出。
use std::fs::File;
use std::io::{self, Read};
fn read_file(filename: &str) -> io::Result<String> {
let mut file = File::open(filename)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
match read_file("example.txt") {
Ok(contents) => println!("File contents: {}", contents),
Err(e) => eprintln!("Error reading file: {}", e),
}
}
Option 类型用于表示可能不存在的值,它有两种变体:Some(T)
和 None
。
使用 Option
rust
fn find_value(values: &[i32], target: i32) -> Option<i32> {
for &value in values.iter() {
if value == target {
return Some(value);
}
}
None
}
fn main() {
let numbers = [1, 2, 3, 4, 5];
match find_value(&numbers, 3) {
Some(value) => println!("Found value: {}", value),
None => println!("Value not found"),
}
}
使用 if let 和 match
fn find_value(values: &[i32], target: i32) -> Option<i32> {
for &value in values.iter() {
if value == target {
return Some(value);
}
}
None
}
fn main() {
let numbers = [1, 2, 3, 4, 5];
if let Some(value) = find_value(&numbers, 3) {
println!("Found value: {}", value);
} else {
println!("Value not found");
}
}
panic! 宏用于处理不可恢复的错误。当程序遇到不可恢复的错误时,会触发一个 panic,导致程序崩溃。
使用 panic!
fn divide(x: i32, y: i32) {
if y == 0 {
panic!("Division by zero");
}
println!("Result: {}", x / y);
}
fn main() {
divide(10, 0); // 触发 panic!
}
Unsafe
Rust 是 Rust 中的一个重要概念,用于处理那些无法通过 Rust 的类型系统和所有权模型自动验证的操作。常见的 unsafe 操作包括指针操作、内存访问等。
// 定义 unsafe 函数
unsafe fn dangerous_operation() {
// 危险操作
let mut x = 5;
let y = &mut x as *mut i32;
*y = 10;
}
fn safe_function() {
// 安全函数调用 unsafe 函数
unsafe {
dangerous_operation();
}
}
fn main() {
safe_function();
}
// 定义 unsafe 指针操作
fn pointer_operations() {
let mut x = 5;
let y = &mut x as *mut i32;
unsafe {
*y = 10;
}
println!("x: {}", x);
}
fn main() {
pointer_operations();
}
// 不安全的类型转换
fn type_casts() {
let mut x = 5;
let y: *const i32 = &x;
unsafe {
let z: *mut i32 = y as *mut i32;
*z = 10;
}
println!("x: {}", x);
}
fn main() {
type_casts();
}
宏是 Rust 中一种强大的元编程工具,用于在编译时生成代码。宏分为两种类型:声明式宏 (macro_rules!
) 和过程宏 (proc_macro
和 proc_macro_derive
).
macro_rules! my_macro {
($val:expr) => {
println!("Value: {}", $val);
};
}
fn main() {
my_macro!(42);
}
过程式宏分为两种:属性宏 (proc_macro_attribute
) 和派生宏 (proc_macro_derive
)。
属性宏
// 属性宏定义
#[proc_macro_attribute]
pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
// 处理输入
let args_str = args.to_string();
let input_str = input.to_string();
format!("{} [{}] {}", args_str, input_str, "processed").parse().unwrap()
}
// 属性宏使用
#[my_attribute]
struct MyStruct {
field: i32,
}
fn main() {
let s = MyStruct { field: 42 };
println!("MyStruct: {:?}", s);
}
派生宏
// 派生宏定义
#[proc_macro_derive(MyDerive)]
pub fn my_derive(input: TokenStream) -> TokenStream {
// 处理输入
let input_str = input.to_string();
format!("{} [derived] {}", input_str, "processed").parse().unwrap()
}
// 派生宏使用
#[derive(MyDerive)]
struct MyStruct {
field: i32,
}
fn main() {
let s = MyStruct { field: 42 };
println!("MyStruct: {:?}", s);
}
全局变量示例
// 定义全局变量
static COUNTER: u32 = 0;
fn increment_counter() {
unsafe {
COUNTER += 1;
}
}
fn main() {
increment_counter();
println!("Counter: {}", COUNTER);
}
Unsafe 指针操作示例
// 定义 unsafe 指针操作
fn pointer_operations() {
let mut x = 5;
let y = &mut x as *mut i32;
unsafe {
*y = 10;
}
println!("x: {}", x);
}
fn main() {
pointer_operations();
}
声明式宏示例
macro_rules! my_macro {
($val:expr) => {
println!("Value: {}", $val);
};
}
fn main() {
my_macro!(42);
}
属性宏示例
// 属性宏定义
#[proc_macro_attribute]
pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
// 处理输入
let args_str = args.to_string();
let input_str = input.to_string();
format!("{} [{}] {}", args_str, input_str, "processed").parse().unwrap()
}
// 属性宏使用
#[my_attribute]
struct MyStruct {
field: i32,
}
fn main() {
let s = MyStruct { field: 42 };
println!("MyStruct: {:?}", s);
}
派生宏示例
// 派生宏定义
#[proc_macro_derive(MyDerive)]
pub fn my_derive(input: TokenStream) -> TokenStream {
// 处理输入
let input_str = input.to_string();
format!("{} [derived] {}", input_str, "processed").parse().unwrap()
}
// 派生宏使用
#[derive(MyDerive)]
struct MyStruct {
field: i32,
}
fn main() {
let s = MyStruct { field: 42 };
println!("MyStruct: {:?}", s);
}
异步编程的概念 异步编程允许程序在等待某些操作完成(如网络请求、文件读取)时执行其他任务。这可以显著提高应用程序的响应性和性能。
async/await 语法
use std::time::Duration;
use tokio::time::sleep;
async fn async_function() {
println!("Starting async function...");
sleep(Duration::from_secs(1)).await; // 模拟耗时操作
println!("Async function completed!");
}
#[tokio::main]
async fn main() {
async_function().await; // 调用异步函数
}
Future 接口 所有异步操作最终都实现了 Future 接口。
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture;
impl Future for MyFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
// 实现具体的逻辑
Poll::Ready(())
}
}
任务调度
通过调用 .poll()
方法来手动推进 Future 的执行,直到它完成或准备好继续执行。
use std::pin::Pin;
use std::task::{Context, Poll};
use std::future::Future;
struct MyFuture;
impl Future for MyFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
// 假设这是一个异步操作
if /* 条件 */ {
Poll::Ready(())
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
事件循环
事件循环负责调度任务,通常由库如 tokio
或 async-std
提供。
#[tokio::main]
async fn main() {
let future = async {
println!("Hello, world!");
};
tokio::spawn(future); // 将任务放入事件循环
}
Pin 概念 使数据结构固定在内存中,防止它们被移动,这对于异步代码特别重要。
use std::pin::Pin;
use std::sync::Arc;
struct MyPinnedStruct;
impl Unpin for MyPinnedStruct {} // 标记为可移动
let pinned_struct: Pin<Box<MyPinnedStruct>> = Pin::new(Box::new(MyPinnedStruct));
Unpin 概念 允许对象在内存中自由移动。
struct MyUnpinnedStruct;
impl Unpin for MyUnpinnedStruct {}
Stream 概念 可以产生一系列值的数据源。
use futures::stream::StreamExt;
let stream = futures::stream::iter(vec![1, 2, 3]);
while let Some(item) = stream.next().await {
println!("Received item: {}", item);
}
结合使用 异步函数可以消费或产生流,使得处理大量数据更加高效。
use futures::stream::StreamExt;
async fn process_stream(stream: impl Stream<Item = i32>) {
while let Some(item) = stream.next().await {
println!("Processing item: {}", item);
}
}
等待多个 Future 同时完成。
use tokio::task::JoinHandle;
#[tokio::main]
async fn main() {
let handle1 = tokio::spawn(async {
println!("Task 1 started");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("Task 1 finished");
});
let handle2 = tokio::spawn(async {
println!("Task 2 started");
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
println!("Task 2 finished");
});
let (res1, res2) = tokio::try_join!(handle1, handle2).unwrap();
}
从多个可能完成的 Future 中选择第一个完成的。
use tokio::select;
#[tokio::main]
async fn main() {
let handle1 = tokio::spawn(async {
println!("Task 1 started");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("Task 1 finished");
});
let handle2 = tokio::spawn(async {
println!("Task 2 started");
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
println!("Task 2 finished");
});
select! {
_ = handle1 => println!("Task 1 completed first"),
_ = handle2 => println!("Task 2 completed first"),
}
}
生命周期管理 确保引用不会超出其被引用的数据的生命周期。
use std::pin::Pin;
use std::sync::Arc;
struct MyData {
value: Arc<i32>,
}
impl MyData {
fn new(value: i32) -> Self {
MyData { value: Arc::new(value) }
}
fn get_value(&self) -> &i32 {
&*self.value
}
}
fn main() {
let data = MyData::new(42);
let ref_value = data.get_value(); // 安全的引用
}
错误处理 正确处理异步操作中的错误,避免程序崩溃。
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct MyError(String);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "My custom error: {}", self.0)
}
}
impl Error for MyError {}
async fn async_function() -> Result<(), MyError> {
println!("Starting async function...");
if /* 条件 */ {
Err(MyError("An error occurred".to_string()))
} else {
Ok(())
}
}
#[tokio::main]
async fn main() {
match async_function().await {
Ok(_) => println!("Async function completed successfully"),
Err(e) => eprintln!("Error: {}", e),
}
}
设置环境 安装必要的依赖库。
cargo new my_async_web_server
cd my_async_web_server
cargo add hyper
cargo add tokio
编写服务端代码 创建 HTTP 服务器并处理请求。
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
let addr = ([127, 0, 0, 1], 3000).into();
let listener = TcpListener::bind(&addr).await.unwrap();
println!("Listening on http://{}", addr);
let server = Server::from_tcp(listener)
.expect("Failed to bind TCP listener")
.serve(make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(|req| async move {
match req.uri().path() {
"/" => {
let body = "Hello, World!";
Ok(Response::new(Body::from(body)))
}
_ => {
let body = "Not Found";
Ok(Response::builder()
.status(404)
.body(Body::from(body))
.unwrap())
}
}
}))
}));
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!