【问题标题】:Boxed trait object is still an unknown size盒装特征对象的大小仍然未知
【发布时间】:2022-12-02 22:43:10
【问题描述】:

错误:

所以我收到以下错误:

error[E0277]: the size for values of type 'dyn Getter' cannot be known at compilation time

struct PlusFive;

impl Operator for PlusFive {
    fn apply<'a>(&self, a: &'a dyn Getter) -> Box<dyn Getter + 'a> {
        Box::new(MapGetter {
            source: a, // A pointer to some Getter
            f: |n:i32| n + 5 // A way to later compute +5 on source
        });
    }
}
  • 特征Sized没有为dyn Getter实现
  • MapGetter&lt;T, F&gt;实现了特征Getter

问题:

我不确定这个错误是什么意思或如何解决它。 dyn Getter 的大小无法知道,但 MapGetter 的大小肯定可以!并且由于 MapGetter 是实现 Getter 特性的具体类型,所以我不明白为什么我不能将其装箱并返回。

我在这里遗漏了一些东西。我能够MapGetter 装箱,我不能做的就是将它提升为特征对象?

如果有助于在上下文中查看所有内容,这是我正在使用的完整示例:


笔记:

总的来说,我一直在尝试通过动态调度来做到这一点。部分是因为我想看看可以做什么,部分是因为我预见到自己想要一个 dyn Operators 的列表,其中下面的具体类型可能会有所不同。

我不想直接将运算符附加到 Getter 特征,因为最终我希望运算符代表可重用的逻辑片段,因此它们可以在事后(或不止一次)应用于 Getter

完整上下文:

trait Getter {
    fn compute(&self) -> i32;

    fn pipe(&self, operator: &dyn Operator) -> Box<dyn Getter>
    where
        Self: Sized,
    {
        operator.apply(&self)
    }
}

impl<T: Getter> Getter for &T {
    fn compute(&self) -> i32 {
        (*self).compute()
    }
}

impl<T: Getter> Getter for Box<T> {
    fn compute(&self) -> i32 {
        (*self).compute()
    }
}

struct PureGetter<T>(T);

impl Getter for PureGetter<i32> {
    fn compute(&self) -> i32 {
        self.0
    }
}

struct MapGetter<T, F> {
    source: T,
        (*self).compute()
    f: F,
}

impl<T, F> Getter for MapGetter<T, F>
where
    T: Getter,
    F: FnMut(i32) -> i32 + Clone,
{
    fn compute(&self) -> i32 {
        (self.f.clone())(self.source.compute())
    }
}

trait Operator {
    fn apply<'a>(&self, a: &'a dyn Getter) -> Box<dyn Getter + 'a>;
}

struct PlusFive;

impl Operator for PlusFive {
    fn apply<'a>(&self, a: &'a dyn Getter) -> Box<dyn Getter + 'a> {
        Box::new(MapGetter {
            source: a,
            f: |n:i32| n + 5
        })
    }
}

fn main() {
    let result = PureGetter(0).pipe(&PlusFive).compute();
    println!("{:#?}", result);
}
error[E0277]: the size for values of type `dyn Getter` cannot be known at compilation time
  --> src/main.rs:71:9
   |
71 | /         Box::new(MapGetter {
72 | |             source: a,
73 | |             f: |n:i32| n + 5
74 | |         })
   | |__________^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn Getter`
   = help: the trait `Getter` is implemented for `MapGetter<T, F>`
note: required for `&dyn Getter` to implement `Getter`
  --> src/main.rs:24:17
   |
24 | impl<T: Getter> Getter for &T {
   |                 ^^^^^^     ^^
   = note: 1 redundant requirement hidden
   = note: required for `MapGetter<&dyn Getter, [closure@src/main.rs:73:16: 73:23]>` to implement `Getter`
   = note: required for the cast from `MapGetter<&dyn Getter, [closure@src/main.rs:73:16: 73:23]>` to the object type `dyn Getter`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `messin` due to previous error

【问题讨论】:

  • 为什么不在结构上而不是在实现上添加特征边界。你会得到更清晰的错误
  • 您能否添加cargo check 提供的完整错误?我试图在操场上查看您的代码,但解决眼前的问题会导致出现几个新问题。所以我不确定这是否与您看到的相同。
  • @Cerberus 当然,我已经用完整的错误更新了问题

标签: rust


【解决方案1】:

此特定错误的最小化示例:

trait Getter {}

impl<T: Getter> Getter for &T {}

impl Getter for () {}

fn main() {
    let getter: &dyn Getter = &();
    let getter: Box<dyn Getter> = Box::new(getter);
}

Playground

原因如下:

  • 要从Box&lt;&amp;dyn Getter&gt;创建Box&lt;dyn Getter&gt;&amp;dyn Getter必须自己实现Getter
  • &amp;TGetter 进行了全面实施。
  • 但是这个实现的通用参数有一个隐含的Sized绑定,因此它不能应用于&amp;dyn Getter

要解决眼前的问题,您可以简单地relax the bound

impl<T: Getter + ?Sized> Getter for &T {}

在您的原始代码中,推理是相似的,只是多了一个中间步骤 - 您必须将 impl Getter 传递给 MapGetter,这样 MapGetter 就是 Getter 本身;但传入的值是&amp;dyn Getter,由于上述原因,它不是Getter


顺便说一句,我想说同时拥有两个引用和Boxes 是很不合常理的。如果您将自己限制在其中一个,您可能会有更简单的方法——要么一直向下借用临时引用,要么Boxing 一切以拥有一切。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 2018-03-19
    • 2018-08-19
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多