Rust中无法为含关联类型成员的结构体派生arbitrary::Arbitrary怎么办
问题1:无大幅重构的解决方案
有两种可行的轻量解决方法,不需要把关联类型改成泛型:
方法1:手动为派生宏指定trait约束
arbitrary::Arbitrary的派生宏支持通过#[arbitrary(bound)]属性手动补充关联类型的约束,直接覆盖宏默认生成的约束规则即可,修改后的代码如下:
use arbitrary::Arbitrary; trait RawData { type Elem; fn hello(); } impl RawData for u8 { type Elem = u32; fn hello() { println!("hi"); } } #[derive(Debug, Clone)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr(feature = "arbitrary", arbitrary(bound = "S::Elem: Arbitrary<'a>"))] pub struct Point<S> where S: RawData, { y: S::Elem, }
这种方式灵活性最高,只会在启用arbitrary feature的时候附加约束,不会影响正常业务逻辑的编译。
方法2:在关联类型定义处加约束
如果你希望所有实现RawData trait的类型的Elem关联类型都必须实现Arbitrary,可以直接在trait定义中为关联类型加全局约束:
use arbitrary::Arbitrary; trait RawData where for<'a> Self::Elem: Arbitrary<'a>, { type Elem; fn hello(); } // 后续实现RawData的类型的Elem必须满足Arbitrary约束 impl RawData for u8 { type Elem = u32; fn hello() { println!("hi"); } } // 此时派生宏可以直接识别约束,不需要额外配置 #[derive(Debug, Clone)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct Point<S> where S: RawData, { y: S::Elem, }
问题2:泛型与关联类型的行为差异原因
这种差异是Rust过程宏派生的通用限制,并非Arbitrary独有的行为:
当为带泛型的结构体自动派生trait时,派生宏的默认逻辑只会为直接出现在结构体字段中的泛型参数添加对应的trait约束:
- 对于
struct Point<S> { x: S }的场景,宏会自动生成impl<'a, S: Arbitrary<'a>> Arbitrary<'a> for Point<S>的实现,约束完全匹配需求,因此只要实际使用的S类型实现了Arbitrary就可以正常编译。 - 对于
struct Point<S: RawData> { y: S::Elem }的场景,宏无法自动推断出需要添加S::Elem: Arbitrary<'a>的约束,默认只会错误地给S本身添加Arbitrary约束,和实际需求不符,因此会直接报关联类型未实现trait的错误。
该限制在Rust官方的过程宏文档中已有明确提及,所有内置派生宏(如Debug、Clone等)和第三方派生宏都遵循同样的规则,遇到关联类型的约束场景都需要用户手动指定边界。
内容的提问来源于stack exchange,提问作者anon2328
相关产品推荐
相关产品推荐

