![](/img/trans.png)
[英]rust - How to use derive macro to parse the meta information of a struct?
[英]How can I use #[derive] on a type containing an array where the length is specified by a macro?
我有这个代码:
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!()],
| ^^^^^^^^
有没有办法在包含数组的类型上使用#[derive]
,其中长度由宏指定?
从Github问题引用我的回答:
它是故意的(这是历史记录 ),但有可能在将来改善情况,至少应该重写错误信息以解释它拒绝编译的原因。
根本问题是
#[derive]
宏需要将其特征需求“转发”到结构的所有字段。 要使MyStruct
成为Debug
,field
类型也必须是Debug
。 考虑一下这个:#[derive(Debug)] struct MyStruct<T: FromStr> { field: T }
我们需要
impl<T: FromStr> Debug for MyStruct<T> where T: Debug { ... }
生成impl<T: FromStr> Debug for MyStruct<T> where T: Debug { ... }
(你会看到为什么我在FromStr
内选择了FromStr
)。 但在这种情况下:#[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!()],
}
解决方案可以是使用两个宏,一个宏定义结构,另一个宏定义大小。
macro_rules! foo {
($x:expr) => {
#[derive(Debug)]
struct MyStruct<T> {
field_list: [T; $x],
}
};
}
macro_rules! bar {
() => {
foo!(1);
};
}
bar!();
如你所说,它适用于非泛型类型。 也许这是一个编译器错误? 我应该在Github上打开一个问题吗?
这可能不是错误,但肯定是宏的限制。 但是,您可以打开一个问题来要求改进它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.