在Rust中是否存在泛型类型擦除(类似于Java)?我找不到明确的答案。
Vec<i32>
和Vec<String>
是不同的类型,因此Vec<i32>::len()
和Vec<String>::len()
是不同的函数。这是必要的,因为Vec<i32>
和Vec<String>
具有不同的内存布局,因此需要不同的机器码!因此,不,没有类型擦除。Any::type_id()
:use std::any::Any;
fn main() {
let v1: Vec<i32> = Vec::new();
let v2: Vec<String> = Vec::new();
let a1 = &v1 as &dyn Any;
let a2 = &v2 as &dyn Any;
println!("{:?}", a1.type_id());
println!("{:?}", a2.type_id());
}
Vec
实例的不同类型ID。这证明了Vec<i32>
和Vec<String>
是不同的类型。Any
。您无法获取运行时值的更多类型信息,例如其名称或成员。为了能够使用Any
,必须将其强制转换(使用Any::downcast_ref()
或Any::downcast_mut()
)为在编译时已知的类型。String
存储在一个 ArrayList<Integer>
中,因为在运行时根本就不存在 ArrayList<Integer>
这样的东西,它只是一个 ArrayList
。在Java中使用泛型的唯一优势是编译器会在安全的情况下为您插入转换操作,而没有泛型则需要自己输入转换操作(并且可能会出错)。 - Francis GagnéVec<Box<Any>>
怎么样? - aochagaviaVec<Box<Any>>
可以让你存储任何实现了Any
的类型的对象,但你不能像使用Vec<i32>
或Vec<String>
那样使用它。在Java中,类型擦除只有在类型参数可以被替换为引用类型(不能使用像int
这样的原始类型)时才可能发生。由于所有引用类型都具有相同的大小(指针),所有泛型类或方法的实例化将是相同的(除了一些奇怪的情况,如new T[]
不起作用)。 - Francis Gagnédyn Trait
进行虚方法分派,这使得您可以拥有一个具有不同具体类型元素的 Vec
:fn main() {
let list: Vec<Box<dyn ToString>> = vec![Box::new(1), Box::new("hello")];
for item in list {
println!("{}", item.to_string());
}
}
请注意,编译器要求您手动包装元素,因为它必须在编译时知道每个值的大小。您可以使用一个Box
,它指向堆,无论它指向什么,它的大小都相同。您也可以使用&
引用:
fn main() {
let list: Vec<&dyn ToString> = vec![&1, &"hello"];
for item in list {
println!("{}", item.to_string());
}
}
然而,需要注意的是,如果您使用&
引用,可能会遇到生命周期问题。