rust - 发送要构造的宏的枚举变量

标签 rust enums macros

目前,我正在一个项目中使用多个返回不同错误的 crate 。我试图不对结果使用unwrap,而是使用问号语法将错误向上传递。
为了做到这一点,我创建了自己的错误枚举,该枚举针对我使用的不同包装箱中的不同类型的错误提供了变体,然后使用map_err将错误映射到我的错误枚举。我还决定将行和文件添加到重新映射错误的位置,以便可以看到遇到错误的位置。
我的错误枚举

#[derive(Debug, Clone)]
pub enum Error {
    GameError(ggez::GameError, String),
    RonError(ron::error::Error, String),
}
映射错误的示例
let rdr = filesystem::open(ctx, gen_conf_path)
    .map_err(|e| {
    Error::GameError(e, format!("at line {} in {}", line!(), file!()))
    })?;
这样做的问题是,我需要发送给map_err的闭包变得很长,并且每次都基本相同,除了我要映射到的enum变体。所以我想创建一个宏,为正确的枚举变量生成闭包。所以我可以写类似下面的东西。
let rdr = filesystem::open(ctx, gen_conf_path).map_err(map_to!(Error::GameError))?
并且map_to!宏将生成我之前拥有的代码。
这可能吗?我可以将枚举变量发送到宏并让其构造它还是应该以完全不同的方式来执行此操作?

最佳答案

关于枚举变量的一个有趣的实现细节是,初始化程序实际上是函数。

We have another useful pattern that exploits an implementation detail of tuple structs and tuple-struct enum variants. These types use () as initializer syntax, which looks like a function call. The initializers are actually implemented as functions returning an instance that’s constructed from their arguments. We can use these initializer functions as function pointers that implement the closure traits, which means we can specify the initializer functions as arguments for methods that take closures

Advanced Functions and Closures - The Rust Programming Language


这意味着,如果您有一个enum FooBar,它具有一个Foo(i32, i32)变体,那么您可以使用FooBar::Foo并将其作为Fn(i32, i32) -> FooBar传递。
enum FooBar {
    Foo(i32, i32),
    Bar(String),
}

fn foo(f: fn(i32, i32) -> FooBar) -> FooBar {
    f(1, 2)
}

fn bar<F>(f: F) -> FooBar
where
    F: Fn(i32, i32) -> FooBar,
{
    f(1, 2)
}

fn main() {
    foo(FooBar::Foo);
    bar(FooBar::Foo);
}

因此,如果您将枚举变量视为函数,那么您的宏将变得非常简单:
macro_rules! map_to {
    ($f:expr) => {
        |e| {
            $f(e, format!("at line {} in {}", line!(), file!()))
        }
    };
}
当然,这是假定e始终是有效类型,相对于map_to所使用的枚举变体而言。

关于rust - 发送要构造的宏的枚举变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66205516/

相关文章:

rust - 如何将元素从盒装切片中移出,在此过程中消耗切片?

static-libraries - Rust 静态库 "unlinked native library"警告

c# - 从枚举 C# 中获取所有底层 ID 的列表

具有多个值和值类型的 Javascript 枚举

iteration - Rust 迭代器和展望(peek/multipeek)

rust - Rust crates(例如 num_cpus)是如何实现的?

c++ - 枚举 "ghost values": what for?

visual-studio - 我可以创建 Visual Studio 宏来在调试器中启动特定项目吗?

macros - Clojure 宏扩展

c - 有什么办法可以输入 "destringify"以便它可以像标识符一样使用吗?