当两个类型参数相同时,如何覆写Rust trait的实现?
Rust 条件Trait实现问题
我定义了一个包含两个类型参数的结构体与一个Trait:
struct MyStruct<T1, T2>{ field1: T1, field2: T2, } trait ToList<T>{ fn to_list(self) -> Vec<T>; }
我希望为该结构体实现这个Trait,且当结构体的两个类型参数相同时,使用一个“更优”的实现:
impl <T> ToList<T> for MyStruct<T, T> { fn to_list(self) -> Vec<T>{ vec![self.field1, self.field2] } } impl <T1, T2> ToList<T1> for MyStruct<T1, T2> { fn to_list(self) -> Vec<T1>{ vec![self.field1] } }
注:第一个实现仅在两个类型参数相同时生效。
这两个实现单独存在时均可编译,但同时定义会产生冲突。我尝试通过typenum库解决,但遇到两个问题:
- 次要问题:编译器似乎无法识别
IsEqual<T1, T2>::Output = True意味着T1与T2是相同类型(不确定是否属于预期行为,可临时绕过) - 主要问题:
typenum::IsEqual似乎未针对任何原生类型实现,我的编译器无法识别该Trait约束。
尝试的代码及报错
我编写了如下代码:
use typenum::{IsEqual, True, False}; fn main() { let struct1 = MyStruct{field1: 1, field2: 2}; let struct2 = MyStruct{field1: 1, field2: true}; let list1 = struct1.to_list(); let list2 = struct2.to_list(); println!("{:?}", list1); println!("{:?}", list2); } struct MyStruct<T1, T2>{ field1: T1, field2: T2, } trait ToList<T, AreEqual>{ fn to_list(self) -> Vec<T>; } impl <T> ToList<T, True> for MyStruct<T, T> { fn to_list(self) -> Vec<T>{ vec![self.field1, self.field2] } } impl <T1, T2> ToList<T1, False> for MyStruct<T1, T2> where T2: IsEqual<T1, Output=False>, { fn to_list(self) -> Vec<T1>{ vec![self.field1] } }
这段代码无法编译,第二个to_list()调用触发如下错误:
the method `to_list` exists for struct `MyStruct<{integer}, bool>`, but its trait bounds were not satisfied method cannot be called on `MyStruct<{integer}, bool>` due to unsatisfied trait bounds main.rs(12, 1): method `to_list` not found for this struct main.rs(12, 1): doesn't satisfy `MyStruct<{integer}, bool>: ToList<{integer}, B0>` main.rs(27, 27): the following trait bounds were not satisfied: `<bool as IsEqual<{integer}>>::Output = B0`
临时可行的方案(局限性大)
我发现如果将bool、i32等原生类型包装到自定义的包装类型中,再为这些包装类型实现IsEqual,代码可以正常编译。但这种方式需要为所有要使用的类型组合编写特定的实现,扩展性极差:
use typenum::{IsEqual, True, False}; struct Wrapped<T>(T); fn main() { let struct1 = MyStruct{field1: 1, field2: 2}; let struct2: MyStruct<i32, bool> = MyStruct{field1: 1, field2: true}; let list1 = struct1.to_list(); let list2 = struct2.to_list(); println!("{:?}", list1); println!("{:?}", list2); } struct MyStruct<T1, T2>{ field1: T1, field2: T2, } trait ToList<T, AreEqual>{ fn to_list(self) -> Vec<T>; } impl <T> ToList<T, True> for MyStruct<T, T> { fn to_list(self) -> Vec<T>{ vec![self.field1, self.field2] } } impl <T1, T2> ToList<T1, False> for MyStruct<T1, T2> where Wrapped<T2>: IsEqual<Wrapped<T1>, Output=False>, { fn to_list(self) -> Vec<T1>{ vec![self.field1] } } impl IsEqual<Wrapped<i32>> for Wrapped<bool>{ type Output = False; fn is_equal(self, rhs: Wrapped<i32>) -> Self::Output { todo!() } } impl IsEqual<Wrapped<i32>> for Wrapped<i32>{ type Output = True; fn is_equal(self, rhs: Wrapped<i32>) -> Self::Output { todo!() } }
请问:我是否遗漏了typenum方案的关键要点?或者有没有更简单、通用性更强的替代方案?
内容的提问来源于stack exchange,提问作者Edward Peters
相关产品推荐
相关产品推荐

