我有这个代码:
macro_rules! count {
() => { 1 };
}
#[derive(Debug)]
struct MyStruct<T> {
field_list: [T; count!()],
}
Run Code Online (Sandbox Code Playgroud)
编译器给出了这个错误:
error: `derive` cannot be used on items with type macros
--> src/main.rs:7:21
|
7 | field_list: [T; count!()],
| ^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
有没有办法#[derive]在包含数组的类型上使用,其中长度由宏指定?
引用我在Github问题上的回答:
这是故意的(这是历史记录),但是将来情况可能会得到改善,至少应该重写错误消息以解释为什么拒绝编译。
根本问题是
#[derive]宏需要将其特征要求“转发”到结构的所有字段。为了MyStruct成为Debug,其类型field也必须是Debug。考虑一下这个:Run Code Online (Sandbox Code Playgroud)#[derive(Debug)] struct MyStruct<T: FromStr> { field: T }我们需要生成(你很快
impl<T: FromStr> Debug for MyStruct<T> where T: Debug { ... }就会明白我为什么选择 )。FromStr然而在这种情况下:Run Code Online (Sandbox Code Playgroud)#[derive(Debug)] struct MyStruct<T> { field: T::Err }这里的字段是关联类型,因此生成的代码实际上需要是
impl<T: FromStr> Debug for MyStruct<T> where T::Err: Debug { ... }.派生宏实际上扫描字段类型以查看它们是否需要绑定
T或关联类型。但如果你使用类型宏,这就破坏了。代码生成无法看透宏,因此它不知道要生成什么边界。当发现这一点时,我们无法决定是否让类型宏急切地扩展(似乎您可能会陷入循环或排序问题),只需将宏复制到子句中
where(派生通常不会这样做,因为它可能会扩展为私有类型,导致生成的代码中出现类型错误),或者其他什么,所以我们下注并使其成为错误。
在遵守派生“策略”的同时,问题无法真正得到解决:(1)它为您生成边界,(2)它只生成可编译的代码。但由于自定义衍生是稳定的,因此您可以使用一些板条箱,例如衍生品,它可以通过让您重写边界来回避问题:
#[derive(Derivative)]
#[derivative(Debug)]
struct MyStruct<T> {
#[derivative(Debug(bound="T: ::std::fmt::Debug"))]
field_list: [T; count!()],
}
Run Code Online (Sandbox Code Playgroud)