Rust语法简析

文摘   2024-08-15 11:27   湖北  

点击上方蓝字 江湖评谈设为关注/星标




闭包

Rust闭包分为借用所有权和获取所有权两个概念,借用即是闭包跟原始程序段借用它的数据,借用了之后原始程序段数据依然可用。获取即闭包跟原始程序段获取它的数据,获取了之后让原始程序段数据失效。获取权的好处是,可以让闭包独立于原始程序,或者不受制于原始程序段的干扰,独立执行。

借用(注意||[表示闭包]表示没有参数,默认闭包借用)所有权:

fn main() {    let x = String::from("Hello");    let closure =|| {    println!("{}", x);    };   // 这里 x 已经被闭包借用,依然可以使用    println!("{}", x); // 这行代码会导致编译错误    closure(); // 现在闭包可以使用 x 的所有权来打印内容}

获取(mov关键字闭包获取)所有权

fn main() {    let x = String::from("Hello");    let closure =mov || {    println!("{}", x);    };   // 这里 x 已经被闭包捕获并移走,不能再在此作用域使用    println!("{}", x); // 这行代码会导致编译错误    closure(); // 现在闭包可以使用 x 的所有权来打印内容}

因为闭包获取了所有权,所以导致了原始程序段失效,编译的时候报错:

error[E0425]: cannot find value `mov` in this scope --> rustfirstproj.rs:3:18  |3 |     let closure =mov || {  |                  ^^^ not found in this scope

带参数的闭包:

let add = |a, b| a + b;println!("{}", add(2, 3)); // 输出: 5


Rust-main

上一篇:Rust编译器研究+.NET9 PreView7 ,提到rust-main从glibc->lang_start->lang_start_internal这个过程,但实际上lang_start_internal里面通过闭包获取所有权调用的rust-main:

fn lang_start_internal(    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),    argc: isize,    argv: *const *const u8,    sigpipe: u8,) -> Result<isize, !> {    use crate::{mem, panic};    let rt_abort = move |e| {        mem::forget(e);      rtabort!("initialization or cleanup bug");    };    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;    let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)        .map_err(move |e| {            mem::forget(e);            rtabort!("drop of the panic payload panicked");        });    panic::catch_unwind(cleanup).map_err(rt_abort)?;    ret_code}

panic概念,在Rust中,panic 是一种用于处理不可恢复错误的机制。当程序遇到无法继续执行的严重错误时,Rust会触发panic,使程序立即停止执行并开始展开(unwind)或直接终止(abort)。

这里需要注意:Rust通过ResultOption类型处理可恢复错误,通过panic处理不可恢复错误。

panic::catch_unwind 是 Rust 标准库中提供的一个函数,用于捕获在 Rust 代码中发生的 panic。它允许你在程序发生 panic 时,进行某种形式的错误恢复或处理,而不是让程序直接崩溃。

use std::panic;
fn main() { let result = panic::catch_unwind(|| { println!("This is a safe block."); panic!("Something went wrong!"); });
match result { Ok(_) => println!("No panic occurred."), Err(err) => println!("Panic occurred: {:?}", err), }}

上面代码引发了panic,被catch_unwind捕获,并将其作为 Err 返回。match 表达式用于检查 catch_unwind 的结果并进行相应的处理。

回到lang_start_internal-》catch_unwind

首先从当前模块(create)

use crate::{mempanic};crate代表当前包(或库)。在Rust中,crate可以理解为一个独立的编译单元或包.通常,一个crate对应一个Cargo.toml文件以及它所管理的源码。当你使用crate::some_module时,实际上是在引用当前包中的some_module模块。
mem和panic都是从当前包的根模块(crate)中导入的模块或函数。这意味着这两个模块或函数是在当前包中定义的,而不是标准库或外部库的一部分。
这行代码的意思:这行代码使用了Rust的use关键字,目的是从当前模块的crate(也就是当前包)中导入mempanic两个模块或函数

闭包的获取,以便后面用到(因为是闭包获取。注意此时rtabort!("initialization or cleanup bug")是失效的,所有权在rt_abort)。

let rt_abort = move |e| {    mem::forget(e);    rtabort!("initialization or cleanup bug");};mem::forget(e) 会丢弃错误 e 而不运行其析构函数。这意味着错误值不会被释放或清理。这种操作通常用于防止内存被自动释放,可能是为了避免一些析构函数中的副作用(如在 panic 过程中再次 panic)。
rtabort! 是一个宏,用于立即终止程序,并打印一条错误消息 "drop of the panic payload panicked"这是在处理 panic 时再次发生 panic 的一种防御性措施。

闭包获取所有权,里面调用了unsafe不安全代码init,以及发生错误的时候处理。这里的rt_abort即上面的闭包获取所有权的rt_abort。

 panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;

unwrap_or

对于 Option<T>,.unwrap_or(default) 方法的作用是:如果 Option 是 Some(T),则返回 T 的值。如果 Option 是 None,则返回提供的 default 值。

继续,重点调用rust-main来了。通过catch_unwind捕获main调用异常,如果没有异常正常返回,如果有异常返回unwrap_or的参数101。外面再嵌套一层catch_unwind,通过map_err闭包获取所有权继续处理异常。可见它这里调用main是非常小心的。

let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)        .map_err(move |e| {            mem::forget(e);            rtabort!("drop of the panic payload panicked"); }); 

调用main完成之后,进行资源清理:

 panic::catch_unwind(cleanup).map_err(rt_abort)?;

这里的cleanup是rust函数:

pub(crate) fn cleanup() {    static CLEANUP: Once = Once::new();    CLEANUP.call_once(|| unsafe {        // Flush stdout and disable buffering.        crate::io::cleanup();        // SAFETY: Only called once during runtime cleanup.        sys::cleanup();    });}

结尾

Rust的语法方面可见简洁度真的是提高了不少

往期精彩回顾

Golang入口彻底研究+CMakelist(Clang)+单文件

从.NET9到Rust

从.NET9看Golang

Rust编译器研究+.NET9 PreView7


江湖评谈
记录,分享,自由。
 最新文章