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

问题描述 投票:0回答:2

我有这个代码(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
与无法拥有该特征的对象(通过动态分派)有什么关系?

rust traits
2个回答
10
投票

trait 类型本身
上拥有 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
方法,这是一个 在其他地方解释 的限制。在这里,调用
s.method_foo();
将中断编译。

请注意,即使该方法根本不使用

Self: Sized
并且可能是可调用的特征对象方法,
Self
约束也会限制编译。


0
投票

一个特质对象,

dyn Trait
不是它的特质,
Trait
,而是一个实际的不同类型,
dyn Trait
,就像
i32
bool
[String]
str
一样是实际不同的类型。但是,在编译类型时不知道
dyn Trait
的大小,就像在编译时不知道
str
[u64]
的大小一样。因此,为
dyn Trait
实现的任何特征都不能是
Sized
,因为
Sized
断言该类型在编译时知道其大小。因此,为了将特征用作特征对象,它一定不需要
Sized

部分复杂性源于编译器自动实现用于限定特征的特征对象:

impl Trait for dyn Trait {}

但是,这只有在 Trait 保持未调整大小的情况下才有可能。 (顺便说一句,特征默认情况下是未调整大小的)。

生锈尺寸

© www.soinside.com 2019 - 2024. All rights reserved.