Generics 在trait对象中使用泛型类型参数的问题是什么?

Generics 在trait对象中使用泛型类型参数的问题是什么?,generics,rust,traits,trait-objects,Generics,Rust,Traits,Trait Objects,我正在阅读,不理解泛型类型参数的问题 使用trait时用具体类型参数填充的泛型类型参数也是如此:具体类型成为实现trait的类型的一部分。当通过使用trait对象忘记了类型时,就无法知道要用什么类型填充泛型类型参数 我试图编写一个示例,但我无法理解它。什么的泛型类型参数 我试图用参数化的trait创建trait对象,但一旦给了参数一个具体的值,它就可以正常工作了: trait Creator<T> { fn create(&self) -> T; } stru

我正在阅读,不理解泛型类型参数的问题

使用trait时用具体类型参数填充的泛型类型参数也是如此:具体类型成为实现trait的类型的一部分。当通过使用trait对象忘记了类型时,就无法知道要用什么类型填充泛型类型参数

我试图编写一个示例,但我无法理解它。什么的泛型类型参数

我试图用参数化的trait创建trait对象,但一旦给了参数一个具体的值,它就可以正常工作了:

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})]
    };
}
trait创建者{
fn创建(&self)->T;
}
struct CreationHouse{
创作者:Vec
}
结构NumCreator{seed:u32}
NumCreator的impl创建者{
fn创建(&self)->u32{
回归自我种子;
}
}
fn main(){
让ch=创意之家{
创建者:vec![Box::new(NumCreator{seed:3}]
};
}
(编译良好,但“未使用”警告除外)

我不明白的是“使用特征时,用具体类型参数填充的泛型类型参数”是什么意思,以及泛型类型如何丢失(因为特征本身“携带”了它们)。如果你能写一个段落中描述的案例,我将不胜感激

“使用特征时,用具体类型参数填充的泛型类型参数”是什么意思

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

trait Foo {
    fn foo<T>(t: T) {}
}
trait Foo{
fn foo(t:t){}
}
当一个函数有一个类型参数时,Rust会为它实际调用的每个类型将函数单形态化(创建一个新副本)。这与trait对象不兼容,因为Rust直到运行时才知道该方法属于哪个impl。

如前所述,对于泛型方法,trait不能是对象安全的

事实证明,原因仅仅是实现限制

通过使用虚拟表(本质上是一个函数指针表)来实现对trait方法正确实现的有效调度。trait对象中的每个方法在虚拟表中获得一个槽,以存储指向函数的一个指针

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

这意味着不可能有指向
fn foo()->T的函数的指针因为它没有代码,所以您可能有一个指向函数的指针,指向一个
fn foo()->i32
,另一个指向函数的指针,指向一个
fn foo()->String
,还有另一个

对于泛型方法,不可能有一个指向函数的指针,因此也不可能有一个v表条目,这使得不可能通过运行时分派调用该方法,即在
dyn Trait
上调用该方法


值得注意的是,出于同样的原因,其他语言也受到同样的限制;C++也不能有模板虚拟方法,例如,

我想我同意原来的段落相当混乱。也许有人应该发送一个PR?我可以说问题是编译器不能跟踪对
foo
的所有调用(因为分派是动态的),因此它不知道应该为哪些t类型单态化
foo
?我不确定我是否理解什么是“调用
foo
”。因为据我所知,特定函数调用的特定实现在运行时可用(通过查找表),这应该足够了,但泛型除外-因为代码应该是单态的,这发生在编译时(?)@Neo我修改了最后一段,希望能澄清这一点。这只是一个实现限制——这使它看起来像是有了正确的拉动请求,Rust可以支持它,但我认为情况并非如此。也许你可以澄清一下如何取消限制?@Shepmaster:我想知道我是否应该这样做。整个程序分析将允许获得
foo
的一组实例化,并为每个实例化创建一个指向函数的指针;永远排除DLL。键入TypeId的HashMaps将允许完全动态的查找,但会增加查找时间。这是一个可解决的问题,但是“解决方案”本身有成本。C++不需要这个,因为C++有继承性。任务:-定义具有调用put(&self,k:&dyn Serialize,v:&dyn Serialize)的API-在rust中不可能。在C++中,您将执行抽象类API {VirtualValuePoT(序列化K,序列化V);}。没有办法在生锈的情况下做同样的事情。我的意见很缺乏。任何实现API的人都必须实现该方法。在生锈的情况下,你是如何做到这一点的?或者没有办法创建此API定义?