代码之家  ›  专栏  ›  技术社区  ›  Anton

Rust是否擦除泛型类型?

  •  18
  • Anton  · 技术社区  · 10 年前

    Rust中是否存在泛型的类型擦除(如Java中)?我找不到确切的答案。

    2 回复  |  直到 10 年前
        1
  •  25
  •   Francis Gagné    5 年前

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

    如果我们使用 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());
    }
    

    我们获得两个实例的不同类型ID Vec 。这支持以下事实: Vec<i32> Vec<字符串> 是不同的类型。

    然而,Rust中的反射能力有限; Any 这是我们目前所拥有的。无法获取有关运行时值类型的详细信息,例如其名称或成员。为了能够与 任何 ,必须使用 Any::downcast_ref() Any::downcast_mut() 转换为编译时已知的类型。

        2
  •  1
  •   Camelid user3426575    5 年前

    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)

    但是,请注意,如果使用 & -你可能会遇到终身问题。