在特征对象中使用泛型类型参数的引用问题是什么?

What is the cited problem with using generic type parameters in trait objects?

我正在阅读 Object Safety Is Required for Trait Objects 但我不明白泛型类型参数的问题。

The same is true of generic type parameters that are filled in with concrete type parameters when the trait is used: the concrete types become part of the type that implements the trait. When the type is forgotten through the use of a trait object, there is no way to know what types to fill in the generic type parameters with.

我正在尝试编写示例代码,但我无法理解它。 what 的通用类型参数?

我试图从参数化的特征中创建一个特征对象,但是一旦参数被赋予了一个具体的值,它就可以正常工作了:

trait Creator<T> {
    fn create(&self) -> T;
}

struct CreationHouse {
    creators: Vec<Box<dyn Creator<u32>>>
}

struct NumCreator { seed: u32 }

impl Creator<u32> for NumCreator {
    fn create(&self) -> u32 {
        return self.seed;
    }
}

fn main() {
    let ch = CreationHouse{
        creators: vec![Box::new(NumCreator{seed: 3})]
    };
}

(编译良好,除了 "unused" 警告)

我不明白它是什么意思 "generic type parameters that are filled in with concrete type parameters when the trait is used" 以及泛型类型怎么会丢失(因为特征 "carries" 它们本身)。如果你能写一个段落中描述的案例的例子,我将不胜感激。

what does it mean "generic type parameters that are filled in with concrete type parameters when the trait is used"

一个不起作用的例子是当类型参数是方法的一部分时:

trait Foo {
    fn foo<T>(t: T) {}
}

当一个函数有一个类型参数时,Rust 会为它实际调用的每个类型单态化函数(制作一个新副本)。这与 trait 对象不兼容,因为 Rust 直到运行时才知道该方法属于哪个 impl。

所述,对于泛型方法,特征不能是对象安全的。

事实证明,原因仅仅是实施限制。

通过使用 virtual-table 实现对 trait 方法正确实现的高效分派,它本质上是指向函数的指针 table。 trait 对象中的每个方法在 virtual-table 中获取 one 槽以存储 one 指向函数的指针。

另一方面,泛型函数或方法根本就不是函数或方法。它是一个蓝图,可以通过用实际的、具体的参数替换通用参数来创建任意多的不同函数或方法。

这意味着不可能有 fn foo<T>() -> T; 的函数指针,因为它没有 code,相反你可能有一个指针一个 fn foo<i32>() -> i32 另一个 的函数指针 fn foo<String>() -> String 和另一个...

不可能有一个指向函数的指针,因此不可能有一个 v-table 条目,对于泛型方法来说,不可能通过 运行-time dispatch 调用该方法,即是 dyn Trait.

没有table其他语言也因为同样的原因受到同样的限制;例如,C++ 也不能有模板虚方法。