如何在包含长度由宏指定的数组的类型上使用#[derive]?

时间:2018-05-11 16:04:00

标签: macros rust

我有这段代码:

{
    "removeme": "SKU-",
    "replacewith": "P-",
    "value": "SKU-37378633"
}

编译器给出了这个错误:

macro_rules! count {
    () => { 1 };
}

#[derive(Debug)]
struct MyStruct<T> {
    field_list: [T; count!()],
}

有没有办法在包含数组的类型上使用error: `derive` cannot be used on items with type macros --> src/main.rs:7:21 | 7 | field_list: [T; count!()], | ^^^^^^^^ ,其中长度由宏指定?

2 个答案:

答案 0 :(得分:3)

从Github问题中引用我的回答:

  

这是故意的(这里是historical record),但有一个   可能的情况可以在未来改善,并在   至少应该重写错误消息以解释它拒绝的原因   编译。

     

根本问题是#[derive]宏需要“转发”   他们对结构的所有字段的特征要求。对于   MyStructDebugfield的类型也必须为Debug。   考虑一下这个:

#[derive(Debug)] struct MyStruct<T: FromStr> {
    field: T
}
     

我们需要生成impl<T: FromStr> Debug for MyStruct<T> where T: Debug { ... }(你会明白为什么我选择了   FromStr   第二)。但在这种情况下:

#[derive(Debug)] struct MyStruct<T> {
    field: T::Err
}
     

此处字段是关联类型,因此实际生成的代码   需要impl<T: FromStr> Debug for MyStruct<T> where T::Err: Debug { ... }

     

派生宏实际上扫描字段类型以查看它们是否存在   需要绑定T或关联类型。但是如果使用类型宏,   这打破了。代码生成无法通过宏看到,所以它   不知道会产生什么界限。

     

当发现这个时,我们无法决定是否让这种类型   宏急切地扩大(似乎你可以进入一个循环或   排序问题),只需将宏复制到where子句中(派生   通常不这样做,因为它可以扩展为私人类型,   导致生成的代码中的类型错误),或something else,所以我们惩罚和   这是一个错误。

在遵守导出的“策略”时,问题无法得到解决:(1)它为你生成边界,(2)它只生成编译的代码。但是由于自定义派生是稳定的,你可以使用的箱子,如derivative,通过让你重写绑定来回避问题:

#[derive(Derivative)]
#[derivative(Debug)]
struct MyStruct<T> {
    #[derivative(Debug(bound="T: ::std::fmt::Debug"))]
    field_list: [T; count!()],
}

答案 1 :(得分:1)

解决方案可以是使用两个宏,一个宏定义结构,另一个宏定义大小。

➜  a npx pkg app.js --target 'host'
> pkg@4.3.1
> Warning Cannot resolve 'nightmareDir'
  /home/someone/Desktop/a/app.js
  Dynamic require may fail at run time, because the requested file
  is unknown at compilation time and not included into executable.
  Use a string literal as an argument for 'require', or leave it
  as is and specify the resolved file name in 'scripts' option.
> Warning Cannot resolve 'electronDir'
  /home/someone/Desktop/a/app.js
  Dynamic require may fail at run time, because the requested file
  is unknown at compilation time and not included into executable.
  Use a string literal as an argument for 'require', or leave it
  as is and specify the resolved file name in 'scripts' option.
➜  a ./app
Example Domain // <-- Our sweet result :D 
➜  a
  

It works on non-generic type as you said.也许这是一个编译器错误?我应该在Github上打开一个问题吗?

这可能不是错误,但肯定是宏的限制。但是,您可以打开一个问题来要求改进它。