Generics 隐藏和接收通用T对象
给出了以下防锈代码:Generics 隐藏和接收通用T对象,generics,rust,dynamic-dispatch,Generics,Rust,Dynamic Dispatch,给出了以下防锈代码: struct Wrapper<T> { data: Vec<T>, // more attributes... } trait DataWrapper<T> { fn get_column(&self) -> &Vec<T>; fn get_data(&self, row: usize) -> &T; } impl<T> DataWrapper
struct Wrapper<T> {
data: Vec<T>, // more attributes...
}
trait DataWrapper<T> {
fn get_column(&self) -> &Vec<T>;
fn get_data(&self, row: usize) -> &T;
}
impl<T> DataWrapper<T> for Wrapper<T> {
fn get_column(&self) -> &Vec<T> {
&self.data
}
fn get_data(&self, row: usize) -> &T {
&self.data[row]
}
}
struct Inter<T> {
inter_value: Wrapper<T>,
}
trait GetInter {
fn get_count(&self) -> &str;
}
impl GetInter for Inter<i32> {
fn get_count(&self) -> &str {
"i32"
}
}
impl GetInter for Inter<f64> {
fn get_count(&self) -> &str {
"f64"
}
}
fn create_vector() -> Vec<Box<GetInter>> {
// Add some sample data
let x = Wrapper { data: vec![1, 2, 3] };
let y = Wrapper { data: vec![1.1, 2.2, 3.3] };
let mut vec: Vec<Box<GetInter>> = Vec::new();
let m = Inter { inter_value: x };
let m = Box::new(m);
let m = m as Box<GetInter>;
vec.push(m);
let n = Inter { inter_value: y };
let n = Box::new(n);
let n = n as Box<GetInter>;
vec.push(n);
vec
}
struct ColumnWrapper {
columns: Vec<Box<GetInter>>, // more attributes
}
fn create_column_wrapper() -> ColumnWrapper {
let result = create_vector();
ColumnWrapper { columns: result }
}
fn main() {
let result = create_column_wrapper();
for iter1 in result.columns {
println!("1: {}", iter1.get_count());
}
}
现在真正的问题开始了。我尝试访问存储在包装器中的原始数据
我的第一个想法是使用Rust的动态调度功能。它应该在运行时检测真实的数据类型
已修改main()
函数:
fn main() {
let result = create_column_wrapper();
for iter1 in result.columns {
println!("1: {}", iter1.get_count());
for iter2 in dyn_dispatch(*iter1) {
println!("2: {}", iter2);
}
}
}
相应且未测试的dyn\u dispatch()
功能:
trait Foo<T> {
fn method(x: &Inter<T>) -> &Vec<T>;
}
impl<i32> Foo<i32> for Inter<i32> {
fn method(x: &Inter<i32>) -> &Vec<i32> {
&x.inter_value.data
}
}
impl<f64> Foo<f64> for Inter<f64> {
fn method(x: &Inter<f64>) -> &Vec<f64> {
&x.inter_value.data
}
}
fn dyn_dispatch<T>(x: &GetInter) -> &Vec<T> {
Foo::method(&x as &Inter<T>)
}
trait Foo{
fn方法(x:&Inter)->&Vec;
}
国际米兰的impl Foo{
fn方法(x:&Inter)->&Vec{
&x、 内部值数据
}
}
国际米兰的impl Foo{
fn方法(x:&Inter)->&Vec{
&x、 内部值数据
}
}
fn动态调度(x:&GetInter)->&Vec{
Foo::方法(&xas&Inter)
}
编译失败,并引发错误:
85:2错误:类型Inter
的traitFoo
实现冲突:[E0119]
你知道如何修复编译错误吗?还有一个更容易隐藏和访问泛型T
对象的方法吗?这里有几个问题
第一个错误:
错误:类型Inter的trait Foo实现冲突:
[E0119]
实际上指的是:
impl<i32> Foo<i32> for Inter<i32> { ... }
impl<f64> Foo<f64> for Inter<f64> { ... }
也就是说,对任何T的Inter
执行Foo
,因此存在冲突的实现。解决方法是将它们写为:
impl Foo<i32> for Inter<i32> { ... }
impl Foo for Inter{…}
下一个问题是,您实际上并没有执行动态调度。您的dyn\u dispatch
函数必须在编译时指定或推断T
;它不能每次返回不同的类型;类似地,您不能像这样从GetInter
向下转换到Inter
。您需要以与之前相同的方式进行操作GetInter::get_count
谢谢您的提示。将函数添加到GetInter
以从Wrapper
返回inter\u值
,需要一个通用函数或特性。后者是不可能的。它将打破非通用数据的ColumnWrapper
思想。只保留泛型函数。它必须如何实现,你能粘贴一个代码片段来解决这个问题吗?如果你隐藏在一个泛型特征后面(没有参数化),调用代码就不能使用实际的类型-编译时它不再可用。您可以实现一个get_float()->选项
,get_int()->选项
等,如果在不支持它的基础类型上调用该选项,则该选项将失败,但如果您有类似于fn get()->t
,则每个实现者都必须使用任何类型。
impl Foo<i32> for Inter<i32> { ... }