为什么特质不能自我构建?

时间:2016-07-02 11:45:22

标签: rust

此代码给出了编译错误:

trait IBoo {
    fn new() -> Box<IBoo>;
}

虽然此代码编译时没有任何错误:

trait IBoo {
    //fn new() -> Box<IBoo>;
}

trait IFoo {
    fn new() -> Box<IBoo>;
}
  1. 为什么第一个不能编译? rustc --explain E0038没有直接暗示我为什么不可能。
  2. 是否可以在一个界面(特征)中组合构造和方法?

2 个答案:

答案 0 :(得分:16)

编译器会告诉您完全这不起作用的原因:

>>> a = [1, 2, 3], [1, 4, 5], [1, 8, 9]
>>> [p for p in product(*a) if len(set(p)) == len(p)]
[(1, 4, 8), (1, 4, 9), (1, 5, 8), (1, 5, 9), (2, 1, 8), (2, 1, 9), (2, 4, 1), (2, 4, 8), (2, 4, 9), (2, 5, 1), (2, 5, 8), (2, 5, 9), (3, 1, 8), (3, 1, 9), (3, 4, 1), (3, 4, 8), (3, 4, 9), (3, 5, 1), (3, 5, 8), (3, 5, 9)]

注意最后一行。它告诉你错误的原因是error[E0038]: the trait `IBoo` cannot be made into an object --> src/main.rs:2:5 | 2 | fn new() -> Box<IBoo>; | ^^^^^^^^^^^^^^^^^^^^^^ the trait `IBoo` cannot be made into an object | = note: method `new` has no receiver 不依赖于实现new()特征的值的实例。

如果没有将某种指针指向IBoo,则动态调度无法调用方法。如果无法通过动态调度调用它,则意味着它无法进入特征的关联vtable。 是一个关联的vtable,因为这就像self 之类的工作。前段时间,核心Rust开发人员决定在特征中包含一个“非对象安全”方法,使整体特征不被用作对象。 / p>

换句话说:因为你已经定义了一个无法动态调度的方法,所以Box<IBoo> trait 作为一个整体被取消了与动态调度一起使用的资格。< / p>

如果你想要某种构造函数,你需要有一些其他的写法。这可能是使用普通函数指针或IBoo特征,就像使用Java一样。

答案 1 :(得分:13)

这来自description of E0038

  

方法没有接收器

     

从那时起,不能调用不带self参数的方法   它不会成为获取指向方法表的指针的方法。

trait Foo {
    fn foo() -> u8;
}
     

这可以称为<Foo as Foo>::foo(),这是不可能的   选择一个实现。

     

添加绑定到这些方法的Self: Sized通常会产生这种情况   编译。

trait Foo {
    fn foo() -> u8 where Self: Sized;
}

你可以这样做:

trait IBoo {
    fn new() -> Box<IBoo>
    where
        Self: Sized;
}

在其他情况下,您可以将限制放在整个impl: