【问题标题】:How to make trait method take &Self parameter如何使 trait 方法采用 &Self 参数
【发布时间】:2021-11-11 04:27:54
【问题描述】:

我正在尝试使用一些默认方法实现来创建特征。其中一种方法必须采用相同类型的实例并执行一些计算。

这是我想要实现的简单示例:

struct A {
    val: f32,
}

trait S {
    fn val(&self) -> f32;

    fn add(&self, other: &Self) -> f32 {
        add(&self, other)
    }
}

impl S for A {
    fn val(&self) -> f32 {
        self.val
    }
}

fn add<T: S>(first: &T, second: &T) -> f32 {
    first.val() + second.val()
}

编译失败,报错:

15 | |     fn add(&self, other: &Self) -> f32 {
16 | |         add(&self, other)
   | |                    ^^^^^ expected `&Self`, found type parameter `Self`
17 | |     }

我不明白错误信息,因为 other 的类型是 &amp;Self 而不是 Self,那么为什么编译器会不这么认为呢?

如果我将其更改为引用 add(&amp;self, &amp;other)(这似乎不对,因为 other 已经是引用类型),我会收到另一个错误:

   |
16 |         add(&self, &other)
   |         ^^^ the trait `S` is not implemented for `&Self`
...
26 | fn add<T: S>(first: &T, second: &T) -> f32 {
   |           - required by this bound in `add`

有没有办法通过默认的 trait 实现来实现这一点,或者这只适用于具体类型(例如在这个问题中:How do I implement the Add trait for a reference to a struct?)?

编辑:如果我将其称为add(self, other),它会尝试发送特征对象,但我想通过引用发送对象。真的,我想发送具体的实现而不是 trait 对象。

error[E0277]: the size for values of type `Self` cannot be known at compilation time
  --> src/main.rs:16:9
   |
16 |         add(self, other)
   |         ^^^ doesn't have a size known at compile-time

【问题讨论】:

  • 如果我把它称为 add(self, other),它会尝试发送 trait 对象 - 你是怎么得出这个结论的?我问是因为我认为它不正确。编译器将Self可能性 保留为未调整大小的对象,这将使&amp;Self 引用可变大小。但是,正如编译器所解释的,您可以通过在 trait 中要求 Sized 轻松选择退出该功能。

标签: rust


【解决方案1】:

您将&amp;self 传递给add(),这使其成为双重引用,并且add() 的参数在类型上不一致。 addT 显然是由第一个参数决定的,这就是为什么编译器似乎期望另一个参数也具有 &amp;&amp;Self 参数的原因。 (阅读错误消息末尾的注释。)

add(self, other) 调用它,它会编译。请注意,您还需要通过添加+ ?Sized 来选择退出绑定在add 上的隐式Sized

// rest as in your code

trait S {
    fn val(&self) -> f32;

    fn add(&self, other: &Self) -> f32 {
        add(self, other)
    }
}

fn add<T: S + ?Sized>(first: &T, second: &T) -> f32 {
    first.val() + second.val()
}

Playground

【讨论】:

  • 看来我误解了 Sized trait 的含义,因为对 trait 对象的混淆。我仍然不明白 ?Sized 是什么意思,但至少我现在知道要搜索什么。谢谢。
  • 我还是不明白 ?Sized 是什么意思, - T: ?Sized 表示允许T 不调整大小,? 去掉了隐含的@987654336 @绑定在类型参数T上。在这种情况下,它允许 add() 使用 trait 对象——但这并不意味着它需要 trait 对象或者它以某种方式将引用转换为 trait 对象;它将接受对具体类型的引用(恰好实现S)就好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2012-05-04
  • 2014-05-19
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
相关资源
最近更新 更多