rust - 了解特征和对象安全

标签 rust traits trait-objects

我正在为对象安全的基础知识苦苦挣扎。如果我有这段代码

struct S {
    x: i32,
}

trait Trait: Sized {
    fn f(&self) -> i32
    where
        Self: Sized;
}

fn object_safety_dynamic(x: Trait) {}

我收到了

error[E0038]: the trait `Trait` cannot be made into an object
  --> src/lib.rs:11:29
   |
5  | trait Trait: Sized {
   |       -----  ----- ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...
...
11 | fn object_safety_dynamic(x: Trait) {}
   |                             ^^^^^ the trait `Trait` cannot be made into an object

当我添加或删除 : Sized 作为超特征或 f 的绑定(bind)时,我收到略有不同的错误消息。

谁能解释一下:

  • 为什么这个特定示例不起作用?本章Trait Objects状态:

    So what makes a method object-safe? Each method must require that Self: Sized

    这不是实现了吗?

  • Trait: Sizedwhere Self: Sized 有什么区别? (嗯,是的,一个继承了 trait,另一个是参数绑定(bind),但是从 Rust 的 trait 对象的角度来看?

  • 要使 object_safety_dynamic 正常工作,我必须进行哪些首选更改?

如果重要的话,我正在使用 rustc 1.19.0-nightly (01951a61a 2017-05-20)

解决关于固定尺寸的评论。

trait TraitB {
    fn f(&self) -> i32
    where
        Self: Sized;

    fn g<T>(&self, t: T) -> i32
    where
        Self: Sized;
}

最佳答案

Why does this particular example not work? The chapter Trait Objects states:

So what makes a method object-safe? Each method must require that Self: Sized

这不是实现了吗?

这个问题实际上是:什么是特征对象

trait 对象 是面向对象范例中的接口(interface):

  • 它公开了一组有限的方法,
  • 应用于未知的具体类型。

应用操作的具体类型是未知的这一事实正是人们使用特征对象的原因,因为它允许以统一的方式操作一组异构类型一直到汇编级别.

然而,具体类型未知的事实意味着包含内存的内存区域的大小未知;因此,特征对象只能在引用指针 之后操作,例如&dyn TraitObject , &mut dyn TraitObjectBox<dyn TraitObject>例如。

在内存级别,它们中的每一个都以相同的方式表示:

  • 指向虚拟表的指针,它是一种结构,在固定偏移处为特征对象的每个“方法”保存一个函数指针,
  • 指向对象实际数据的指针。

What is the difference between Trait: Sized and where Self: Sized? (Well, yes, one inherits the trait the other one is a parameter bound, but from Rust's trait object perspective?)

Rust 中没有继承。在两种情况下,它们都是边界:

  • Trait: Sized指出特征本身只能为已经实现 Sized 的类型实现,
  • fn method(&self) where Self: Sized指出只有实现 Sized 的类型可以实现这个方法。

注意:当实现一个 trait 时,所有的方法最终都必须有一个定义;因此后者只有在为带有 Self: Sized 的方法提供默认实现时才真正有用。绑定(bind),如is shown here .

What is the preferred change I had to make object_safety_dynamic work?

您必须通过引用或指针获取特征对象。使用引用还是指针取决于您是否要转让所有权。

关于rust - 了解特征和对象安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44096235/

相关文章:

rust - 如何将可变状态移动到闭包中?

rust - 如何提供可选泛型作为 macro_rules 参数?

PHP 特征 : is there a proper way to ensure that class using a trait extends a super class which contains certain method?

c++ - 类型别名和不完整的类型

rust - 如何将 Arc 克隆传递给闭包?

syntax - `impl TraitX for TraitY` 在 Rust 中意味着什么?

function - 如何从不将 vec 作为参数的回调内部将值存储在 Vec 中?

class - 来自 Python 的类接口(interface)设计可以在 Rust 中得到反射(reflect)吗?

generics - 可克隆类型和可复制类型的特征

rust - 如何将生命周期应用于 VecDeque<Box<dyn Trait>>?