【问题标题】:Does Rust erase generic types or not?Rust 是否擦除泛型类型?
【发布时间】:2015-09-13 03:36:57
【问题描述】:

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

【问题讨论】:

标签: rust type-erasure


【解决方案1】:

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

如果我们使用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&lt;i32&gt;Vec&lt;String&gt; 是不同类型的事实。

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

【讨论】:

  • 看来你我不同意^_^。也许我错过的问题有细微差别......
  • @Shepmaster:在 Java 中,类型擦除是相关的,因为就好像类型参数不存在一样。例如,您可以将String 存储在ArrayList&lt;Integer&gt; 中,因为在运行时没有ArrayList&lt;Integer&gt; 这样的东西;它只是一个ArrayList。在 Java 中使用泛型的唯一好处是编译器会在安全的地方为您插入类型转换,而没有泛型,您必须自己键入类型转换(而且您可能会弄错)。
  • Vec&lt;Box&lt;Any&gt;&gt; 呢?
  • @aochagavia:我不认为这种类型的擦除与在 Java 中的方式相同。 Vec&lt;Box&lt;Any&gt;&gt; 将允许您存储实现 Any 的任何类型的对象,但您不能像使用 Vec&lt;i32&gt;Vec&lt;String&gt; 一样使用它。在 Java 中,类型擦除是唯一可能的,因为类型参数只能用引用类型替换(你不能使用像 int 这样的原始类型)。由于所有引用类型都具有相同的大小(指针),因此泛型类或方法的所有实例都是相同的(除了一些奇怪的东西,例如 new T[] 不起作用)。
【解决方案2】:

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,无论它指向什么,它都具有相同的大小,因为它只是指向堆的指针。你也可以使用&amp;-references:

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

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

(playground)

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

【讨论】:

    猜你喜欢
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多