【问题标题】:Macro that generates formatters dynamically in Rust在 Rust 中动态生成格式化程序的宏
【发布时间】:2017-01-08 13:46:24
【问题描述】:

我正在编写一个宏来为包含单个泛型类型的给定结构动态生成DisplayDebug 等格式化程序。代码如下:

macro_rules! create_formatters {
    ($type_name:ident < $gen_param:ident > ,  $t:path) => {
        impl<$gen_param: $t> $t for $type_name<$gen_param> {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                let output = match stringify!($t) {
                    "std::fmt::Display" => format!("{}", self.0),
                    "std::fmt::Debug" => format!("{:?}", self.0),
                    // other formatters will be implemented soon
                };
                write!(f, "Content is: {}", output)
            }
        }
    };
}

宏由create_formatters!(MyStruct&lt;T&gt;, std::fmt::Display);create_formatters!(MyStruct&lt;T&gt;, std::fmt::Debug);调用

编译器给出以下错误:

error[E0277]: the trait bound `T: std::fmt::Debug` is not satisfied
  --> <anon>:8:58
   |
8  |                     "std::fmt::Debug" => format!("{:?}", self.0),
   |                                                          ^^^^^^ the trait `std::fmt::Debug` is not implemented for `T`
...
28 | create_formatters!(Swagger<T>, std::fmt::Display);
   | -------------------------------------------------- in this macro invocation
   |
   = help: consider adding a `where T: std::fmt::Debug` bound
   = note: required by `std::fmt::Debug::fmt`

我该如何解决?

【问题讨论】:

    标签: struct macros rust traits formatter


    【解决方案1】:

    为什么会出现这个错误?我们来看看create_formatters!(MyStruct&lt;T&gt;, std::fmt::Display);的扩展:

    impl<T: std::fmt::Display> std::fmt::Display for MyStruct<T> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            let output = match "std::fmt::Display" {
                "std::fmt::Display" => format!("{}", self.0),
                "std::fmt::Debug" => format!("{:?}", self.0),
                // other formatters will be implemented soon
            };
            write!(f, "Content is: {}", output)
        }
    }
    

    这里,T 仅限于 Display,但在 impl-body 内部的某处,您使用 {:?} 格式化程序和类型 T。是的,{:?} 的匹配情况永远不会在运行时执行,但编译器在一般情况下无法知道这一点。仍然需要生成每个匹配臂的代码!而这显然是不可能做到的。

    如何解决?

    可能最简洁的解决方案是完全避免使用格式化字符串。如果你有一个 T 类型的变量实现了一个 trait,你可以直接调用 trait 的方法:

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 2018-06-28
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多