发送要构造的宏的枚举变量 [英] Sending which enum variant to for a macro to construct

查看:41
本文介绍了发送要构造的宏的枚举变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Currently, I'm working on a project where I use several crates that return different errors. I'm trying to not use unwrap on a result but instead passing the error upwards using the question mark syntax. To be able to do this I created my own error enum that has variants for the different types of errors from the different crates I'm using and then use map_err to map the errors to my error enum. I also decided that I should add the line and file where I remapped the error so I could see where I encountered the error.

#[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变体.所以我想创建一个宏,为正确的枚举变量生成闭包.所以我可以写类似下面的内容.

The problem with that is that the closure I need to send to map_err becomes quite long and is essentially the same every time except for the enum variant I'm mapping to. So I want to create a macro that generates the closure for the correct enum variant. So i could write something like the following.

let rdr = filesystem::open(ctx, gen_conf_path).map_err(map_to!(Error::GameError))?

然后 map_to!宏将生成我之前拥有的代码.
这可能吗?我可以将枚举变量发送到宏并让它构造它吗,还是应该以完全不同的方式来做到这一点?

And the map_to! macro would generate the code i had before.
Is this possible? Can I send an enum variant to a macro and let it construct it or should I do this in a completely different way?

推荐答案

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

An interesting implementation detail about enum variants, is that the initializers are actually functions.

我们还有另一个有用的模式,该模式利用了元组结构和元组结构枚举变量的实现细节.这些类型使用()作为初始化语法,看起来像一个函数调用.初始化程序实际上是作为函数返回的,该函数返回根据其参数构造的实例.我们可以将这些初始化函数用作实现闭包特征的函数指针,这意味着我们可以将初始化函数指定为采用闭包的方法的参数

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

这意味着,如果您有一个 FooBar 枚举,并且它具有一个 Foo(i32,i32)变体,则可以使用并传递 FooBar::Foo 作为 Fn(i32,i32)->FooBar .

This means, that if you had an enum FooBar, which had a variant Foo(i32, i32), then you could use and pass FooBar::Foo as a 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);
}


因此,如果您将枚举变量视为函数,那么宏将变得非常简单:


Thus if you think of your enum variant as function, then your macro becomes quite simple:

macro_rules! map_to {
    ($f:expr) => {
        |e| {
            $f(e, format!("at line {} in {}", line!(), file!()))
        }
    };
}

这当然是假设 e 始终是有效类型,相对于与 map_to 相关的枚举变量而言.

This is of course assuming that e is always the valid type, in relation to the enum variant used in relation to map_to.

这篇关于发送要构造的宏的枚举变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆