Rust会删除泛型类型吗?

时间:2015-09-13 03:36:58

标签: rust type-erasure

Rust中是否有类型擦除泛型(如Java中)?我无法找到明确的答案。

2 个答案:

答案 0 :(得分:13)

当您使用泛型函数或泛型类型时,编译器会为每个不同的类型参数集生成一个单独的实例(我相信生命周期参数会被忽略,因为它们对生成的代码没有影响)。此过程称为单态化。例如,Vec<i32>Vec<String>是不同的类型,因此Vec<i32>::len()Vec<String>::len()是不同的功能。这是必要的,因为Vec<i32>Vec<String>具有不同的内存布局,因此需要不同的机器代码!因此,,没有类型擦除。

如果我们使用Any::get_type_id()(暂时不稳定,所以必须使用夜间编译器编译),如下例所示:

#![feature(get_type_id)]

use std::any::Any;

fn main() {
    let v1: Vec<i32> = Vec::new();
    let v2: Vec<String> = Vec::new();

    let a1 = &v1 as &Any;
    let a2 = &v2 as &Any;

    println!("{:?}", a1.get_type_id());
    println!("{:?}", a2.get_type_id());
}

我们为Vec的两个实例获取不同的类型ID。这支持Vec<i32>Vec<String>是不同类型的事实。

然而,Rust的反射能力有限; Any几乎就是我们现在所拥有的一切。您无法获取有关运行时值类型的更多信息,例如其名称或其成员。为了能够使用Any,您必须使用Any::downcast_ref()Any::downcast_mut()将其强制转换为编译时已知的类型。

答案 1 :(得分:0)

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());
    }
}

(playground)

请注意,编译器要求您手动将元素装箱,因为它必须在编译时知道每个值的大小。您可以使用Box,它指向的大小相同,因为它只是指向堆的指针。您还可以使用&-引用:

fn main() {
    let list: Vec<&dyn ToString> = vec![&1, &"hello"];

    for item in list {
        println!("{}", item.to_string());
    }
}

(playground)

但是,请注意,如果使用&-引用,则可能会遇到生命周期问题。