简体   繁体   English

Rust 是否会擦除泛型类型?

[英]Does Rust erase generic types or not?

Is there type erasure of generics in Rust (like in Java) or not? Rust 中是否存在泛型类型擦除(如 Java)? I am unable to find a definitive answer.我无法找到明确的答案。

When you use a generic function or a generic type, the compiler generates a separate instance for each distinct set of type parameters (I believe lifetime parameters are ignored, as they have no influence on the generated code).当您使用泛型函数或泛型类型时,编译器会为每个不同的类型参数集生成一个单独的实例(我相信生命周期参数会被忽略,因为它们对生成的代码没有影响)。 This process is called monomorphization .这个过程称为单态化 For instance, Vec<i32> and Vec<String> are different types, and therefore Vec<i32>::len() and Vec<String>::len() are different functions.例如, Vec<i32>Vec<String>是不同的类型,因此Vec<i32>::len()Vec<String>::len()是不同的函数。 This is necessary, because Vec<i32> and Vec<String> have different memory layouts, and thus need different machine code!这是必要的,因为Vec<i32>Vec<String>具有不同的内存布局,因此需要不同的机器码! Therefore, no , there is no type erasure.因此,,没有类型擦除。

If we use Any::type_id() , as in the following example:如果我们使用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());
}

we obtain different type IDs for two instances of Vec .我们为Vec两个实例获得不同的类型 ID。 This supports the fact that Vec<i32> and Vec<String> are distinct types.这支持Vec<i32>Vec<String>是不同类型的事实。

However, reflection capabilities in Rust are limited;然而,Rust 中的反射能力是有限的; Any is pretty much all we've got for now. Any几乎就是我们现在所拥有的。 You cannot obtain more information about the type of a runtime value, such as its name or its members.您无法获得有关运行时值类型的更多信息,例如其名称或其成员。 In order to be able to work with Any , you must cast it (using Any::downcast_ref() or Any::downcast_mut() to a type that is known at compile time.为了能够使用Any ,您必须将其Any::downcast_ref()使用Any::downcast_ref()Any::downcast_mut()为编译时已知的类型。

Rust does have type erasure in the form of virtual method dispatch viadyn Trait , which allows you to have a Vec where the elements have different concrete types: 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) (操场)

Note that the compiler requires you to manually box the elements since it must know the size of every value at compile time.请注意,编译器要求您手动装箱元素,因为它必须在编译时知道每个值的大小。 You can use a Box , which has the same size no matter what it points to since it's just a pointer to the heap.您可以使用Box ,无论它指向什么,它都具有相同的大小,因为它只是一个指向堆的指针。 You can also use & -references:您还可以使用& -references:

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

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

(playground) (操场)

However, note that if you use & -references you may run into lifetime issues.但是,请注意,如果您使用& -references,您可能会遇到生命周期问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM