Rust全局变量、宏编程与asnyc/await异步编程

目录全局变量错误处理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 类型: 表示可能出错的操作。
  • Option 类型: 表示可能不存在的值。
  • panic! 宏: 用于处理不可恢复的错误。
  • 自定义错误类型: 可以定义自己的错误类型来更好地描述错误。

Result 类型

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 类型

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,导致程序崩溃。

使用 panic!

fn divide(x: i32, y: i32) {
    if y == 0 {
        panic!("Division by zero");
    }
    println!("Result: {}", x / y);
}

fn main() {
    divide(10, 0);  // 触发 panic!
}

unsafeRust

Unsafe Rust 是 Rust 中的一个重要概念,用于处理那些无法通过 Rust 的类型系统和所有权模型自动验证的操作。常见的 unsafe 操作包括指针操作、内存访问等。

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();
}

macro宏编程

宏是 Rust 中一种强大的元编程工具,用于在编译时生成代码。宏分为两种类型:声明式宏 (macro_rules!) 和过程宏 (proc_macroproc_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);
}

asnyc/await异步编程

异步编程基础

异步编程的概念 异步编程允许程序在等待某些操作完成(如网络请求、文件读取)时执行其他任务。这可以显著提高应用程序的响应性和性能。

async/await 语法

  • 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 接口 所有异步操作最终都实现了 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
        }
    }
}

事件循环 事件循环负责调度任务,通常由库如 tokioasync-std 提供。

#[tokio::main]
async fn main() {
    let future = async {
        println!("Hello, world!");
    };

    tokio::spawn(future); // 将任务放入事件循环
}

Pin 和 Unpin

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 {}

async/await 和 Stream 流处理

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

join!

等待多个 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();
}

select!

从多个可能完成的 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),
    }
}

实践应用:构建 Async Web 服务器

设置环境 安装必要的依赖库。

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);
    }
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
天涯学馆
天涯学馆
0x9d6d...50d5
资深大厂程序员,12年开发经验,致力于探索前沿技术!