有没有办法在宏中获取结构的字段名称?

时间:2015-05-01 11:30:15

标签: rust macros

考虑以下示例:

struct S {
    a: String,
    b: String,
}

我有一个像这样调用的宏:

my_macro!(S);

我想在宏中访问结构的字段名称,如下所示:

macro_rules! my_macro {
    ($t:ty) => {{
        let field_names = get_field_names($t);
        // do something with field_names
    }};
}

我是Rust和宏的新手,所以也许我错过了一些明显的东西。

2 个答案:

答案 0 :(得分:18)

宏在解析过程中会或多或少地扩展;它无法访问AST或类似的东西 - 它可以访问的是你传递给它的东西,my_macro!(S)纯粹是应该有一个名为S的类型。

如果您将结构定义为宏的一部分,那么您可以了解字段:

macro_rules! my_macro {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty,)*
    }) => {
        struct $name {
            $($field_name: $field_type,)*
        }

        impl $name {
            // This is purely an example—not a good one.
            fn get_field_names() -> Vec<&'static str> {
                vec![$(stringify!($field_name)),*]
            }
        }
    }
}

my_macro! {
    struct S {
        a: String,
        b: String,
    }
}

// S::get_field_names() == vec!["a", "b"]

...但这虽然可能有用,但往往是一件可疑的事情。

答案 1 :(得分:2)

这是另一种不需要编写宏的可能性(但是,字段名称将在运行时解析):

version: "2"

services:
  app:
    image: nginx
    ports:
      - "9000:80"
  discovery:
    image: consul
    ports:
       - "8500:8500"
    command: agent -server -bootstrap-expect 1 -ui -data-dir /tmp -client=0.0.0.0

    docker version
    Client:
    Version:      1.10.3
    API version:  1.22
    Go version:   go1.5.3
    Git commit:   8acee1b
    Built:
    OS/Arch:      linux/amd64

    Server:
    Version:      1.10.3 


    docker-compose version
    docker-compose version 1.7.1, build 0a9ab35
    docker-py version: 1.8.1
    CPython version: 2.7.11
    OpenSSL version: OpenSSL 1.0.2e 3 Dec 2015

(此解决方案需要extern crate rustc_serialize; use rustc_serialize::json::{Encoder, Json}; use rustc_serialize::json::Json::Object; use rustc_serialize::Encodable; #[derive(Default, RustcEncodable)] struct S { a: String, b: String, } fn main() { let mut json = "".to_owned(); { let mut encoder = Encoder::new(&mut json); S::default().encode(&mut encoder).unwrap(); } let json = Json::from_str(&json).unwrap(); if let Object(object) = json { let field_names: Vec<_> = object.keys().collect(); println!("{:?}", field_names); } } 包)

已添加rustc-serialize以避免必须手动创建结构(但仍会创建结构)。

此解决方案的工作原理是将结构编码为JSON格式的derive(Default)并将其解码为String。从Json对象中,我们可以提取字段名称(如果它是Json变体)。

一种可能更有效的方法是编写自己的编码器:

Object

可以这样使用:

struct FieldNames {
    names: Vec<String>,
}

impl FieldNames {
    fn new() -> FieldNames {
        FieldNames {
            names: vec![],
        }
    }
}

struct FieldsEncoder<'a> {
    fields: &'a mut FieldNames,
}

impl<'a> FieldsEncoder<'a> {
    fn new(fields: &mut FieldNames) -> FieldsEncoder {
        FieldsEncoder {
            fields: fields,
        }
    }
}

type EncoderError = ();

impl<'a> Encoder for FieldsEncoder<'a> {
    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.fields.names.push(f_name.to_owned());
        Ok(())
    }

    type Error = EncoderError;
    fn emit_nil(&mut self) -> Result<(), Self::Error> { Err(()) }
    fn emit_usize(&mut self, _v: usize) -> Result<(), Self::Error> { Err(()) }
    fn emit_u64(&mut self, _v: u64) -> Result<(), Self::Error> { Err(()) }
    fn emit_u32(&mut self, _v: u32) -> Result<(), Self::Error> { Err(()) }
    fn emit_u16(&mut self, _v: u16) -> Result<(), Self::Error> { Err(()) }
    fn emit_u8(&mut self, _v: u8) -> Result<(), Self::Error> { Err(()) }
    fn emit_isize(&mut self, _v: isize) -> Result<(), Self::Error> { Err(()) }
    fn emit_i64(&mut self, _v: i64) -> Result<(), Self::Error> { Err(()) }
    fn emit_i32(&mut self, _v: i32) -> Result<(), Self::Error> { Err(()) }
    fn emit_i16(&mut self, _v: i16) -> Result<(), Self::Error> { Err(()) }
    fn emit_i8(&mut self, _v: i8) -> Result<(), Self::Error> { Err(()) }
    fn emit_bool(&mut self, _v: bool) -> Result<(), Self::Error> { Err(()) }
    fn emit_f64(&mut self, _v: f64) -> Result<(), Self::Error> { Err(()) }
    fn emit_f32(&mut self, _v: f32) -> Result<(), Self::Error> { Err(()) }
    fn emit_char(&mut self, _v: char) -> Result<(), Self::Error> { Err(()) }
    fn emit_str(&mut self, _v: &str) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum<F>(&mut self, _name: &str, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_arg<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option_none(&mut self) -> Result<(), Self::Error> { Err(()) }
    fn emit_option_some<F>(&mut self, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_seq<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_seq_elt<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map<F>(&mut self, _len: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map_elt_key<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
    fn emit_map_elt_val<F>(&mut self, _idx: usize, _f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { Err(()) }
}