繁体   English   中英

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

[英]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成为Debugfield类型也必须是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM