Trait Object is not Object-safe 错误
Trait Object is not Object-safe error
以下代码无法为我编译。
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
是特征中唯一存在的函数,它可以正常编译和运行。但是我的代码需要这样的模式 - 我该怎么做?
编辑: 此处给出了上述问题的正确答案 ()。但是如果我从函数签名中删除 &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 对象的方法是动态分配的,因此程序会选择在运行时调用的实际方法。这些方法必须具有相同的行为,即接受相同数量的相同大小(成对)的参数和相同大小的 return 值。如果一个方法在其签名中的某处使用了 Self
,比如 fun2
,它的实现将不会相互兼容,因为它们需要对不同大小的值进行操作,因此这样的方法不能统一
这样的方法(不能用于 trait 对象)被称为对象不安全(或非对象安全)。如果一个特征包含这样的方法,它就不能成为一个特征对象——它也被称为对象不安全。
我认为,您可以将特征 return 设为特征对象:
fn fun2(&self) -> Option<Box<A>>
现在解除了对实际类型的依赖,特征再次成为对象安全的。
好吧,错误消息几乎说明了眼前的问题:您正试图在对象上下文中使用非对象安全特征,但您不能那样做。
您可以从特征 A
中删除 fun2
,并在不同的特征中定义它:它的存在将阻止 A
被用作 "trait object" ;所以&A
、Box<A>
等就都无从谈起了。然后每种类型都可以实现这两个特征。
另一种选择是更改fun2
,使其结果不包含Self
类型;你的例子太抽象了,但 Option<Box<A>>
可以接受吗?
至于为什么:为了将特征用作特征对象,编译器必须能够为特征的方法生成一个虚表,以便它可以进行动态的运行时分派。这意味着特征中的每个方法都必须可以用相同的类型实现(self
参数是一个特例)。那么 fun2
return 是什么意思?它必须 return 和 Option<Box<Self>>
,但是 Self
是每个实现的不同类型!没法统一!
以下代码无法为我编译。
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
是特征中唯一存在的函数,它可以正常编译和运行。但是我的代码需要这样的模式 - 我该怎么做?
编辑: 此处给出了上述问题的正确答案 (&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 对象的方法是动态分配的,因此程序会选择在运行时调用的实际方法。这些方法必须具有相同的行为,即接受相同数量的相同大小(成对)的参数和相同大小的 return 值。如果一个方法在其签名中的某处使用了 Self
,比如 fun2
,它的实现将不会相互兼容,因为它们需要对不同大小的值进行操作,因此这样的方法不能统一
这样的方法(不能用于 trait 对象)被称为对象不安全(或非对象安全)。如果一个特征包含这样的方法,它就不能成为一个特征对象——它也被称为对象不安全。
我认为,您可以将特征 return 设为特征对象:
fn fun2(&self) -> Option<Box<A>>
现在解除了对实际类型的依赖,特征再次成为对象安全的。
好吧,错误消息几乎说明了眼前的问题:您正试图在对象上下文中使用非对象安全特征,但您不能那样做。
您可以从特征 A
中删除 fun2
,并在不同的特征中定义它:它的存在将阻止 A
被用作 "trait object" ;所以&A
、Box<A>
等就都无从谈起了。然后每种类型都可以实现这两个特征。
另一种选择是更改fun2
,使其结果不包含Self
类型;你的例子太抽象了,但 Option<Box<A>>
可以接受吗?
至于为什么:为了将特征用作特征对象,编译器必须能够为特征的方法生成一个虚表,以便它可以进行动态的运行时分派。这意味着特征中的每个方法都必须可以用相同的类型实现(self
参数是一个特例)。那么 fun2
return 是什么意思?它必须 return 和 Option<Box<Self>>
,但是 Self
是每个实现的不同类型!没法统一!