rust - Trait Object is not Object-safe 错误

标签 rust

以下代码无法为我编译。

trait A {
    fn fun0(&self);
    fn fun2(&self) -> Option<Box<Self>>;
}

struct B0 {
    id: usize,
}

impl A for B0 {
    fn fun0(&self) { println!("Value: {:?}", self.id); }
    fn fun2(&self) -> Option<Box<Self>> { Option::None }
}

struct B1 {
    id: isize,
}

impl A for B1 {
    fn fun0(&self) { println!("Value: {:?}", self.id); }
    fn fun2(&self) -> Option<Box<Self>> { Option::Some(Box::new(B1 { id: self.id, })) }
}

enum C {
    None,
    Put { object: Box<A>, },
}

fn fun1(values: Vec<C>) {
    for it in values.iter() {
        match *it {
            C::Put { object: ref val, } => val.fun0(),
            C::None => (),
        };
    }
}

fn main() {
    let obj_b0 = Box::new(B0 { id: 778, });
    let obj_b1 = Box::new(B1 { id: -8778, });
    let obj_c0 = C::Put { object: obj_b0, };
    let obj_c1 = C::Put { object: obj_b1, };
    let mut vec = Vec::new();
    vec.push(obj_c0);
    vec.push(obj_c1);
    fun1(vec);
}

报错:

cargo run
   Compiling misc v0.0.1 (file:///home/spandan/virtualization/coding/my/rust-tests/misc/misc)
src/main.rs:188:48: 188:54 error: the trait `A` is not implemented for the type `A` [E0277]
src/main.rs:188             C::Put { object: ref val, } => val.fun0(),
                                                               ^~~~~~
src/main.rs:197:35: 197:41 error: cannot convert to a trait object because trait `A` is not object-safe [E0038]
src/main.rs:197     let obj_c0 = C::Put { object: obj_b0, };
                                                  ^~~~~~
src/main.rs:197:35: 197:41 note: method `fun2` references the `Self` type in its arguments or return type
src/main.rs:197     let obj_c0 = C::Put { object: obj_b0, };
                                                  ^~~~~~
src/main.rs:198:35: 198:41 error: cannot convert to a trait object because trait `A` is not object-safe [E0038]
src/main.rs:198     let obj_c1 = C::Put { object: obj_b1, };
                                                  ^~~~~~
src/main.rs:198:35: 198:41 note: method `fun2` references the `Self` type in its arguments or return type
src/main.rs:198     let obj_c1 = C::Put { object: obj_b1, };
                                                  ^~~~~~
error: aborting due to 3 previous errors
Could not compile `misc`.

一起工作

rustc --version
rustc 1.0.0-nightly (00978a987 2015-04-18) (built 2015-04-19)

问题出现在 fun2(&self) 被带入图片时。如果 fun0 是特征中唯一存在的函数,它可以正常编译和运行。但是我的代码需要这样的模式 - 我该怎么做?

编辑: 此处给出了上述问题的正确答案 (https://stackoverflow.com/a/29985438/1060004)。但是,如果我从函数签名中删除 &self(即,使其成为静态的),我会遇到同样的问题:

fn fun2() -> Option<Box<A>>

现在有什么问题?

最佳答案

正如您所注意到的,当您删除 fun2 方法时,问题就消失了。让我们更仔细地看看它:

fn fun2(&self) -> Option<Box<Self>>;

请注意,其输出类型包含Self,即实现特征的类型。例如,如果 A 是为 String 实现的,它将是 String:

impl A for String {
    fn fun2(&self) -> Option<Box<String>> { ... }
}

但是!对于 trait 对象,值的实际类型被删除,关于 trait 对象,我们唯一知道的就是它是一个实现了 trait 的值,但我们不知道实际类型该特性是为实现的。 Trait 对象的方法是动态分配的,因此程序会选择在运行时调用的实际方法。这些方法必须具有相同的行为,即接受相同数量的相同大小(成对)的参数并返回相同大小的值。如果一个方法在其签名中的某处使用了 Self,例如 fun2,它的实现将不会相互兼容,因为它们需要对不同大小的值进行操作,并且因此这些方法不能统一。

这样的方法(不能用于 trait 对象)被称为对象不安全的(或不是对象安全的)。如果一个特征包含这样的方法,它就不能成为一个特征对象——它也被称为对象不安全。

我认为可行的方法是让特征返回一个特征对象:

fn fun2(&self) -> Option<Box<A>>

现在解除了对实际类型的依赖,特征再次成为对象安全的。

关于rust - Trait Object is not Object-safe 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29985153/

相关文章:

rust - 为什么 Serde 不能为仅包含 &Path 的结构派生反序列化?

rust - Rust 的 clippy 可以自动更正/自动修复吗?

rust - 如何从现在算起 5 分钟?

rust - 尝试在Wasm堆中保存字符串,然后将指向该字符串的指针保存在结构中时,使用“RuntimeError : Memory access out of bounds”

rust - 是否可以在不实现 `Index` 特征的情况下通过字段名称获取结构中的值?

rust - 如果 strong_count 为 1 且 weak_count 为 0,包含 `Send` 的 `Rc` 结构是否安全?

vim - Rust 自动完成在 Vim 中不起作用

rust - 链接 self 的生命周期和方法中的引用

error-handling - 如果Option为Some,返回Err的惯用方式

rust - 在 Rust 中访问新类型