< 返回版块

adminSxs 发表于 2021-05-11 09:45

  • toml
validator = { version="0.13", features = ["derive"] }
serde={version="1",features=["derive"]}
serde_json="1"

main.rs

#[macro_use]
extern crate serde;




macro_rules! generate_modal {
    ($name:ident,$(($variant:ident:$typ:ty $(,#[$attr:meta])*)), *)=>{
        #[derive(Debug,Deserialize,Serialize,::std::default::Default)]
        pub struct $name{
            $(
              $(#[$attr])*
              $variant:$typ,
            )*
        }
    };
}
generate_modal(Modal,(name:String));

fn main(){

  let modal = Modal::default();

}


上面的宏没有加入 validator::Validate macro,能正常生成代码并且能正常编译运行,修改宏

macro_rules! generate_modal {
    ($name:ident,$(($variant:ident:$typ:ty $(,#[$attr:meta])*)), *)=>{
        #[derive(Debug,Deserialize,Serialize,::validator::Validate,::std::default::Default)]
        pub struct $name{
            $(
              $(#[$attr])*
              $variant: $typ,
            )*
        }
    };
}

//新增了::validator::Validate,编译报错: Type `Option < String >` of field `name` not supported

validator: github 地址(https://github.com/Keats/validator)

评论区

写评论
作者 adminSxs 2021-05-12 08:41

老哥,受教了。非常感谢!!

--
👇
modraedlau: 在解决这个问题前,我们来看下dtolnayrust-quiz第9题:https://dtolnay.github.io/rust-quiz/9

macro_rules! m {
    (1) => { print!("1") };
    ($tt:tt) => { print!("2") };
}

macro_rules! e {
    ($e:expr) => { m!($e) };
}

macro_rules! t {
    ($tt:tt) => { e!($tt); m!($tt); };
}

fn main() {
    t!(1);
}

我稍微机翻了部分作者的答案:

这个问题涉及宏匹配器在匹配宏元变量方面的行为。

从上述代码的底部开始,调用t!(1)t!第一个规则匹配,t!(1)被扩展为e!(1); m!(1);

调用e!(1)e!的第一个规则匹配。作为该匹配的一部分,表达式1被打包到一个称为的不透明表达式标记中$e。在随后的任何时候,macro_rules!任何宏都不可能查看$e。唯一可以知道的$e就是某种表达。

在任何情况下,都e!(1)将扩展为m!($e),其中$e包含的不透明表达式1m!($e)自然与m!的第一个规则不匹配,因为$e是不透明的。相反,它与m!第二个规则匹配所以打印出2

之后e!(1)有一个m!(1)的扩展(来自t!的调用)。那确实符合m!的第一个规则打印出1。所以该程序最后的输出为21

大多数片段描述符都具有变成不透明标记的行为,但有些则不然。匹配一次后不透明的描述符:

  • $:block
  • $:expr
  • $:item
  • $:literal
  • $:meta
  • $:pat
  • $:path
  • $:stmt
  • $:ty

其余描述符则不会变得不透明(也就是一直是透明的),可以通过后续规则进行检查:

  • $:ident
  • $:lifetime
  • $:tt

例子:

macro_rules! m {
    ('a) => {};
}

macro_rules! l {
    ($l:lifetime) => {
        // $l is not opaque.
        m!($l);
    }
}

l!('a);

看了这道题后再回到这个问题可以知道,首先我们有generate_modal!宏,它中间又包裹了derive宏,那么加上Validatederive宏报错说类型不正确,由此可以大胆推断很可能是这个类型未被Validatederive宏识别,也就是没有透明传递!原因就是因为使用了$:ty来标识类型,而这个在后续的derive宏中是不透明的。

那么如何解决也非常简单了,将$:ty改成$:tt便可:

#[macro_use]
extern crate serde;

macro_rules! generate_modal {
    ($name:ident, $(($variant:ident: $typ:tt$(, #[$attr:meta])*)),*) => {
        #[derive(Debug, Deserialize, Serialize, ::validator::Validate, ::std::default::Default)]
        pub struct $name {
            $(
              $(#[$attr])*
              $variant: $typ,
            )*
        }
    };
}
generate_modal!(Modal, (name: String, #[validate(email)]));

fn main() {
    let _modal = Modal::default();
}
modraedlau 2021-05-11 14:51

在解决这个问题前,我们来看下dtolnayrust-quiz第9题:https://dtolnay.github.io/rust-quiz/9

macro_rules! m {
    (1) => { print!("1") };
    ($tt:tt) => { print!("2") };
}

macro_rules! e {
    ($e:expr) => { m!($e) };
}

macro_rules! t {
    ($tt:tt) => { e!($tt); m!($tt); };
}

fn main() {
    t!(1);
}

我稍微机翻了部分作者的答案:

这个问题涉及宏匹配器在匹配宏元变量方面的行为。

从上述代码的底部开始,调用t!(1)t!第一个规则匹配,t!(1)被扩展为e!(1); m!(1);

调用e!(1)e!的第一个规则匹配。作为该匹配的一部分,表达式1被打包到一个称为的不透明表达式标记中$e。在随后的任何时候,macro_rules!任何宏都不可能查看$e。唯一可以知道的$e就是某种表达。

在任何情况下,都e!(1)将扩展为m!($e),其中$e包含的不透明表达式1m!($e)自然与m!的第一个规则不匹配,因为$e是不透明的。相反,它与m!第二个规则匹配所以打印出2

之后e!(1)有一个m!(1)的扩展(来自t!的调用)。那确实符合m!的第一个规则打印出1。所以该程序最后的输出为21

大多数片段描述符都具有变成不透明标记的行为,但有些则不然。匹配一次后不透明的描述符:

  • $:block
  • $:expr
  • $:item
  • $:literal
  • $:meta
  • $:pat
  • $:path
  • $:stmt
  • $:ty

其余描述符则不会变得不透明(也就是一直是透明的),可以通过后续规则进行检查:

  • $:ident
  • $:lifetime
  • $:tt

例子:

macro_rules! m {
    ('a) => {};
}

macro_rules! l {
    ($l:lifetime) => {
        // $l is not opaque.
        m!($l);
    }
}

l!('a);

看了这道题后再回到这个问题可以知道,首先我们有generate_modal!宏,它中间又包裹了derive宏,那么加上Validatederive宏报错说类型不正确,由此可以大胆推断很可能是这个类型未被Validatederive宏识别,也就是没有透明传递!原因就是因为使用了$:ty来标识类型,而这个在后续的derive宏中是不透明的。

那么如何解决也非常简单了,将$:ty改成$:tt便可:

#[macro_use]
extern crate serde;

macro_rules! generate_modal {
    ($name:ident, $(($variant:ident: $typ:tt$(, #[$attr:meta])*)),*) => {
        #[derive(Debug, Deserialize, Serialize, ::validator::Validate, ::std::default::Default)]
        pub struct $name {
            $(
              $(#[$attr])*
              $variant: $typ,
            )*
        }
    };
}
generate_modal!(Modal, (name: String, #[validate(email)]));

fn main() {
    let _modal = Modal::default();
}
作者 adminSxs 2021-05-11 14:15

谢谢,我去提一个issue

--
👇
uno: 是validator derive的一个bug

uno 2021-05-11 13:39

是validator derive的一个bug

1 共 4 条评论, 1 页