如何将特征作为结构的拥有字段?

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

我是 Rust 的新手,我想实现一个结构,该结构可以具有不同的结构,这些结构将共同特征实现为字段

在带有垃圾收集器的传统编程语言中,我会这样实现它:


pub struct MemoryMapper {
    regions: Vec<Region>,
}

trait MemoryMappable: Sized {
    
}

pub struct Region {
    device: dyn MemoryMappable,
    start: u32,
    end: u32,
    remap: bool
}

但是我这里有如下编译错误:

the size for values of type `(dyn MemoryMappable + 'static)` cannot be known at compilation time
the trait `Sized` is not implemented for `(dyn MemoryMappable + 'static)`
only the last field of a struct may have a dynamically sized type
change the field's type to have a statically known size

我已经尝试使 Sized 成为 MemoryMappable 的超特性,但它仍然给我以下代码带来问题:

pub fn map(&mut self, device: dyn MemoryMappable, start: u32, end: u32, remap: bool) -> &Region {
        self.regions.insert(0, Region{device, start, end, remap});
        return self.regions.get(0).unwrap();
}
the trait `MemoryMappable` cannot be made into an object
`MemoryMappable` cannot be made into an object

因为来自关于对象安全的 Rust 文档

Sized 不能是一个超特质。换句话说,它不能要求 Self: Sized。

我现在不知道该怎么做

rust struct traits borrow-checker
1个回答
1
投票

结构的字段存在于堆栈中,因此在编译时必须具有已知大小。这就是 Sized 错误的意思。

dyn Trait 是“实现 Trait 的任何类型。那么它的大小是多少?好吧,这取决于底层类型是什么。

因此,dyn Trait 永远不会实现 Sized,即使 Trait 具有 Sized 作为超特征(所有这一切都是为了保证任何实现 Trait 的类型也实现 Sized,但您仍然不知道它是哪个)。

事实上,使 Sized 成为 Trait 的超特征就是您选择退出对象安全的方式,这使得构建 dyn Trait.

变得不可能

相反,解决这个问题的方法是使用类似指针的类型:

  • Box<dyn Trait> 创建一个拥有的指针
  • &dyn Trait 创建参考
  • Arc<dyn Trait> 创建一个引用计数指针

指针类型的选择取决于您的用例,但在大多数情况下,Box<dyn Trait> 很好,并且是一个很好的起点。

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