简体   繁体   中英

Does Rust erase generic types or not?

Is there type erasure of generics in Rust (like in Java) or not? 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. This is necessary, because Vec<i32> and Vec<String> have different memory layouts, and thus need different machine code! Therefore, no , there is no type erasure.

If we use Any::type_id() , as in the following example:

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 . This supports the fact that Vec<i32> and Vec<String> are distinct types.

However, reflection capabilities in Rust are limited; Any is pretty much all we've got for now. 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.

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:

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. You can also use & -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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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