macros - 使用宏保持结构字段可见性

标签 macros rust metaprogramming encapsulation

我正在尝试编写一个允许我使用字段名称和结构声明类型的 Rust 宏,但我仍然需要发出该结构。

我已经使用可选属性、结构的可见性(感谢 The Little Book of Rust Macros ),但无法弄清楚如何处理 pub 在个人中的可选存在字段。

到目前为止我有:

macro_rules! with_generic {
    ($(#[$struct_meta:meta])*
    pub struct $name:ident { $($fname:ident : $ftype:ty), *}
    ) => {
        with_generic![(pub) $(#[$struct_meta])* struct $name {$($fname: $ftype) ,*}];
    };

    ($(#[$struct_meta:meta])*
    struct $name:ident { $($fname:ident : $ftype:ty), *}
    ) => {
        with_generic![() $(#[$struct_meta])* struct $name {$($fname: $ftype), *}];
    };

    (
    ($($vis:tt)*)
    $(#[$struct_meta:meta])*
    struct $name:ident { $($fname:ident : $ftype:ty), *}
    ) => {
        // emit the struct here
        $(#[$struct_meta])*
        $($vis)* struct $name {
            $($fname: $ftype,)*
        }

        // I work with fname and ftypes here
    }
}

它适用于类似

的东西
with_generic! {
    #[derive(PartialEq, Eq, Debug)]
    pub struct Person {
        first_name: String,
        last_name:  String
    }
}

with_generic! {
    #[derive(PartialEq, Eq, Debug)]
    struct PrivatePerson {
        first_name: String,
        last_name:  String
    }
}

但不适用于

with_generic! {
    #[derive(PartialEq, Eq, Debug)]
    struct MixedPerson {
        pub first_name: String,
        last_name:  String
    }
}

我想获得一些关于如何使宏在最后一个案例中工作的帮助。我觉得我可能在这里遗漏了一些基本的东西,比如用于绑定(bind)可见性的类型。如果有一种方法可以在获取字段名称和类型的同时绑定(bind)整个结构树,那也很好。

我还想了解如何让它与具有生命周期参数的结构一起工作,但也许这应该是一个单独的问题。

最佳答案

你不能。至少,不是一个单一的非递归规则。这是因为 Rust 没有用于可见性的宏匹配器。

parse-macros crate 包含一个 parse_struct!显示完全解析 struct 定义所需工作的宏。简短版本:您需要单独解析每个字段,每个“有 pub”和“没有 pub”都有一个规则。

我还要注意的是,另一种情况下您的宏还没有考虑:字段上的属性,这是文档注释工作所必需的。

很快,宏 1.1 应该会稳定下来,这可能会提供一种更简单的方法(假设您可以将宏表示为派生,并且不关心旧版本的 Rust)。

关于macros - 使用宏保持结构字段可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42003501/

相关文章:

java - 安卓工作室 : how to use the fbc live template

c++ - 在类之外声明 C++ 方法?

rust - Rust 语法 `if let [.., last] = self ...` 是什么意思?

c++ - 从命令行定义源文件的宏

vim - 你能在 vim 中做交互式宏或录音吗?

rust - 如何将 IpAddr 转换为 IPv4Addr?

rust - Rust 书的模式部分中的匹配阴影示例非常令人费解

c# - 通过反射或类似方式动态生成属性 getter/setter

c++ - 如何在折叠期间获取成员类型的 boost::mpl 占位符

使用 switch case 设置和获取成员变量的 C++ 元编程