特征对象不是对象安全错误 [英] Trait Object is not Object-safe error

查看:40
本文介绍了特征对象不是对象安全错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码不适合我编译.

The following code does not compile for me.

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 是 trait 中唯一存在的函数,它编译并运行良好.但是我的代码需要这样的模式 - 我该怎么做?

The problem appears when fun2(&self) is brought into the picture. It compiles and runs fine if fun0 is the only existing function in the trait. But my code needs such a pattern - How do i do it ?

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

the correct answer for the above has been given here (https://stackoverflow.com/a/29985438/1060004) . But i am running into the same problem if i remove the &self from function signature (ie., make it static):

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

现在有什么问题?

推荐答案

如您所见,当您删除 fun2 方法时,问题就消失了.让我们更仔细地看一下:

As you have noticed, the problem vanishes when you remove fun2 method. Let's look at it more closely:

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

请注意,它的输出类型包含 Self,即实现 trait 的类型.例如,如果为 String 实现了 A,它将是 String:

Note that its output type contains Self, that is, the type which the trait is implemented for. For example, if A is implemented for String, it would be String:

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

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

However! With the trait objects the actual type of the value is erased, and the only thing that we know about trait objects is that it is a value which implements the trait, but we don't know the actual type the trait is implemented for. Trait object methods are dispatched dynamically, so the program selects the actual method to call at runtime. These methods have to behave identically, that is, accept the same number of parameters of the same size (pairwise) and return values of the same size too. If a method uses Self somewhere in its signature, like fun2, its implementations won't be compatible with each other because they would need to operate on values of different size, and hence such methods can't be unified.

此类方法(不能与 trait 对象一起使用)被称为对象不安全(或非对象安全).如果一个 trait 包含这样的方法,它就不能成为一个 trait 对象——它也被称为非对象安全的.

Such methods (which can't work with trait objects) are called object-unsafe (or not object-safe). If a trait contains such methods, it can't be made a trait object - it is also called not object-safe.

我相信,你可以让 trait 返回一个 trait 对象:

What would work, I believe, is that you can make the trait return a trait object:

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

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

Now the dependency on the actual type is lifted, and the trait becomes object-safe again.

这篇关于特征对象不是对象安全错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆