需要Sized的特征与无法拥有该特征的特征对象有什么关系?

时间:2018-12-31 13:20:53

标签: rust traits

我有此代码(playground):

trait NodeLike: Sized {}

fn main() {
    let s: Box<NodeLike> = panic!();
}

哪个不编译:

error[E0038]: the trait `NodeLike` cannot be made into an object
 --> src/main.rs:4:12
  |
4 |     let s: Box<NodeLike> = panic!();
  |            ^^^^^^^^^^^^^ the trait `NodeLike` cannot be made into an object
  |
  = note: the trait cannot require that `Self : Sized`

我读完所有书后,仍然不明白为什么它不能编译以及为什么没有Sized约束就可以编译。

据我所知:

  • Box<NodeLike>被视为Box<dyn NodeLike>,它使用动态分派进行方法调用。
  • Box<NodeLike>的大小始终与项目类型无关。
  • 大小/非大小理论是必要的,因为有些类型的大小在事前就不知道(例如数组或字符串)。
  • 特征上的Sized标记强制实现类型的大小。

要求实现类型为Sized与不能具有该特征的对象(通过动态调度)有什么关系?

1 个答案:

答案 0 :(得分:1)

特征类型本身具有Self: ?Sized是特征对象(即“对象安全”)的必需属性,即使您可以在特征类型对象上具有impl具有Self: ?Sized类型的Sized特征。因此感到困惑。

这是RFC 255中所定义的缺点,它涉及对象安全(警告:过时的Rust语法)。

这是一本很长的书,但是替代方法之一是仅通过分析特征的方法来确定“对象安全性”。 RFC承认,具有此限制将使某些本来可以不编译的代码生效。 (“这是一项重大更改,并禁止了一些目前合法的安全代码。” )。

如果我们仅将限制降低到实际需要它的特征成员函数,则可以解决此问题。这样编译:

trait NodeLike {
    fn method_foo(&self) -> Self where Self : Sized;
}

fn main() {
    let s: Box<NodeLike> = panic!();
    // Compiles!
}

但是,我们无法通过特征对象调用那些Self: Sized方法,这是explained elsewhere的限制。在这里,调用s.method_foo();将中断编译。

请注意,Self: Sized约束限制了编译,即使该方法根本不使用Self,否则也可能是可调用特征对象方法。