Rust:如何在嵌套泛型结构体中调用泛型方法?
问题:将外部枚举转换为自定义泛型结构体时的编译错误
场景与代码
需要处理一个来自外部Rust crate的枚举,它包含不同数值类型:
pub enum Variables { Float(f32), Double(f64) }
希望将其转换为自定义的泛型数据结构,并封装在另一个结构体中添加元数据:
#[derive(Debug, Clone, PartialEq, Eq)] pub struct MyWrapperVar<T> { num: i8, id: String, var: MyVar<T>, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MyVar<T> { name: String, value: T, }
为了方便序列化,给MyVar和MyWrapperVar实现了new函数:
impl MyVar<f32> { fn new(name: &str, value: f32) -> Self { Self { name: name.to_string(), value, } } } impl MyVar<f64> { fn new(name: &str, value: f64) -> Self { Self { name: name.to_string(), value, } } } impl<T> MyWrapperVar<T> { fn new( num: i8, id: &str, variable_name: &str, variable_value: T, ) -> MyWrapperVar<T> { Self { num, id: id.to_string(), var: MyVar::<T>::new(variable_name, variable_value), } } }
原本计划通过匹配Variables枚举调用MyWrapperVar::new:
fn main() { let var1 = Variables::Float(0.1); match var1 { Variables::Float(v) => { let bla = MyWrapperVar::new(0, "bla", "var1", v); } Variables::Double(v) => { let bla = MyWrapperVar::new(0, "bla", "var1", v); } } }
编译错误
运行时出现如下错误:
error[E0599]: no function or associated item named `new` found for struct `MyVar<T>` in the current scope --> src/main.rs:42:30 | 9 | pub struct MyVar<T> { | ------------------- function or associated item `new` not found for this struct ... 42 | var: MyVar::<T>::new(variable_name, variable_value), | ^^^ function or associated item not found in `MyVar<T>` | = note: the function or associated item was found for - `MyVar<f32>` - `MyVar<f64>` For more information about this error, try `rustc --explain E0599`.
问题原因
MyWrapperVar::new是泛型实现,其中调用了MyVar::<T>::new,但MyVar的new方法仅针对f32和f64两种具体类型实现,并没有为泛型参数T提供通用的new实现。编译器无法保证所有可能的T类型都拥有new方法,因此报错。
解决方案
方案1:为MyVar实现泛型的new方法
直接给MyVar添加泛型的new实现,覆盖所有类型,这样就不需要单独为f32和f64写实现了:
impl<T> MyVar<T> { fn new(name: &str, value: T) -> Self { Self { name: name.to_string(), value, } } }
此时原有的MyWrapperVar泛型new方法可以正常工作,因为任何T类型都能调用MyVar::new。
方案2:为MyWrapperVar针对具体类型实现new
如果不想给MyVar添加泛型new,可以为MyWrapperVar分别针对f32和f64实现new方法:
impl MyWrapperVar<f32> { fn new(num: i8, id: &str, variable_name: &str, variable_value: f32) -> Self { Self { num, id: id.to_string(), var: MyVar::new(variable_name, variable_value), } } } impl MyWrapperVar<f64> { fn new(num: i8, id: &str, variable_name: &str, variable_value: f64) -> Self { Self { num, id: id.to_string(), var: MyVar::new(variable_name, variable_value), } } }
这样main中的匹配调用也能正常编译,因为此时MyWrapperVar::new针对f32和f64都有具体实现。
方案3:在枚举匹配中直接构造MyVar
跳过MyWrapperVar的泛型new,在匹配枚举时直接手动构造MyVar和MyWrapperVar:
fn main() { let var1 = Variables::Float(0.1); match var1 { Variables::Float(v) => { let bla = MyWrapperVar { num: 0, id: "bla".to_string(), var: MyVar { name: "var1".to_string(), value: v, }, }; } Variables::Double(v) => { let bla = MyWrapperVar { num: 0, id: "bla".to_string(), var: MyVar { name: "var1".to_string(), value: v, }, }; } } }
这种方式不需要依赖new方法,直接通过结构体字面量构造,避免了泛型约束问题。
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

