Rust元组中的trait object——期望是trait object,但实际上找到的是类型。

4

我一直在读《Rust编程语言》第17章的Trait对象,并尝试在我的代码中使用Trait对象。

请问为什么函数test2不能编译,而其他函数可以?

trait Print {
    fn print(&self) -> String;
}

impl Print for i32 {
    fn print(&self) -> String {
        return format!("{}", &self);
    }
}

impl Print for &str {
    fn print(&self) -> String {
        return format!("'{}'", &self);
    }
}

pub fn test1() {
    let mut v: Vec<(usize, Box<dyn Print>)> = Vec::new();
    let bxx = Box::new(0);
    let idx = 1;
    v.push((idx, bxx));
    
    for (idx, val) in &v {
        println!("{} - {}", idx, val.print());
    }
}

pub fn test2() {
    let mut v: Vec<(usize, Box<dyn Print>)> = Vec::new();
    let bxx = Box::new(0);
    let idx = 2;
    let t = (idx, bxx);
    v.push(t);
    
    for (idx, val) in &v {
        println!("{} - {}", idx, val.print());
    }
}

pub fn test3() {
    let mut v: Vec<(usize, Box<dyn Print>)> = Vec::new();
    v.push((3, Box::new("a")));
    
    for (idx, val) in &v {
        println!("{} - {}", idx, val.print());
    }
}




fn main() {

    test1();
    test2();
    test3();

}

游乐场


很奇怪,将bxx转换为dyn Print的Box后编译成功了,也许是类型推断使bxx成为了i32的Box而不是dyn Print的Box,但我仍然不明白为什么它不能编译。 - Rafaelplayerxd YT
唯一的区别是 v.push((idx, bxx));let t = (idx, bxx); v.push(t);,后者失败了。这是因为当 let t = (idx, bxx); 时,元组的类型由编译器确定了吗? - rustyhu
1个回答

0

默认情况下,当进行装箱操作时,它会将其视为您要装箱的特定类型的盒子。在您的情况下,应该是Box<i32>。如果您明确注释类型,则可以正常工作:

pub fn test2() {
    let mut v: Vec<(usize, Box<dyn Print>)> = Vec::new();
    let bxx: Box<dyn Print> = Box::new(0);
    let idx = 2;
    let t = (idx, bxx);
    v.push(t);
    
    for (idx, val) in &v {
        println!("{} - {}", idx, val.print());
    }
}

游乐场


那么...如果是这样,为什么test1编译通过了呢?在test1中,bxx不也应该被构造成Box<i32>而不是Box<dyn Print>吗? - fvall
出于相同的原因,在示例1中,您直接向向量推入元素而没有使用 t,因此在这种情况下类型被省略。在第二个示例中,您正在创建 t,因此它将创建类型 (usize,Box<i32>) 的变量 t - Netwave
好的。不太确定我完全理解了,可能是因为我对省略规则的了解不足。既然它确实解决了问题,我会接受这个答案。谢谢! - fvall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接