Rust 是否擦除泛型类型?
Does Rust erase generic types or not?
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>
是不同类型的事实。
但是,Rust 中的反射功能是有限的; Any
几乎就是我们目前所拥有的全部内容。您无法获取有关运行时值类型的更多信息,例如其名称或其成员。为了能够使用 Any
,您必须将其强制转换(使用 Any::downcast_ref()
or Any::downcast_mut()
转换为编译时已知的类型。
Rust 确实通过 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
,无论它指向什么,它都具有相同的大小,因为它只是一个指向堆的指针。您还可以使用 &
-references:
fn main() {
let list: Vec<&dyn ToString> = vec![&1, &"hello"];
for item in list {
println!("{}", item.to_string());
}
}
但是,请注意,如果您使用 &
-引用,您可能 运行 进入生命周期问题。
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>
是不同类型的事实。
但是,Rust 中的反射功能是有限的; Any
几乎就是我们目前所拥有的全部内容。您无法获取有关运行时值类型的更多信息,例如其名称或其成员。为了能够使用 Any
,您必须将其强制转换(使用 Any::downcast_ref()
or Any::downcast_mut()
转换为编译时已知的类型。
Rust 确实通过 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
,无论它指向什么,它都具有相同的大小,因为它只是一个指向堆的指针。您还可以使用 &
-references:
fn main() {
let list: Vec<&dyn ToString> = vec![&1, &"hello"];
for item in list {
println!("{}", item.to_string());
}
}
但是,请注意,如果您使用 &
-引用,您可能 运行 进入生命周期问题。