是否可以通过特征在结构中存储值?

时间:2014-11-19 15:43:33

标签: rust traits lifetime

  

编者注:此代码示例来自1.0之前的Rust版本,并且在语法上不是有效的Rust 1.0代码。此代码的更新版本会产生不同的错误,但答案仍包含有价值的信息。

无论是否有Box,无论是否有生命,我都尝试过这个:

trait TraitToImpl {
    fn do_something(self, val: i32);
}

struct Cont {
    value: i32,
}

impl TraitToImpl for Cont {
    fn do_something(self, val: i32) {
        println!("{}", val);
    }
}

struct StoreTrait<'a> {
    field: Box<TraitToImpl + 'a>,
}

fn main() {
    let cont = Box::new(Cont { value: 12 }) as Box<TraitToImpl>;
    let a = StoreTrait { field: cont };
    a.field.do_something(123);
}

我得到的只是这个错误:

error: cannot convert to a trait object because trait `TraitToImpl` is not object-safe

2 个答案:

答案 0 :(得分:8)

问题是,正如错误消息所说,特征TraitToImpl不是对象安全的。也就是说,通过引用(即&TraitToImplBox<TraitToImpl>使用该特定特征不安全

具体而言,do_something方法按值self获取。考虑一下:编译器如何<{>>调用这个方法Cont放在Box<TraitToImpl>?它必须将值复制到Cont类型的参数中(这是impl所期望的),但此调用必须适用于任何类型的任何类型大小可能会实现TraitToImpl

实际结果:如果您的特征包含按值self或泛型,则不能通过引用使用它。在调用发生时,编译器不再具有足够的信息来实际生成必要的代码。

也许尝试取代&self? :)

答案 1 :(得分:3)

要了解此错误的来源,也可以在Object Safety RFC中查找 object-safe 的定义:

  

我们说特征m上的方法T是对象安全的,如果它是合法的(在当前的Rust中)来调用x.m(...) x类型{{1} },即&T是一个特质对象。如果x中的所有方法都是对象安全的,那么我们说T是对象安全的。

正如@DK所指出的那样,T是非法的,因为x.do_something(...)无法通过值传递。

请注意,通过从非对象安全特征派生,也可以违反对象安全性。 E.g。

TraitToImpl

不会是对象安全的,因为trait TraitToImpl : Clone { fn do_something(&self, val: int); // this method is object-safe } 本身有一个非对象安全的方法(Clone)。