【问题标题】:Static method in trait dynamic dispatchtrait 动态调度中的静态方法
【发布时间】:2015-10-25 00:10:13
【问题描述】:

试图让动态调度在 trait 静态方法中工作,但获取类型必须是已知的错误。

我正在尝试实现类似的目标

是使 trait 通用化的唯一方法吗?

pub struct Aggregate<T: AggregateRoot>
{
    pub id: Uuid,
    agg: T,
    changes:  Vec<Box<Any>>
}

impl <T :AggregateRoot > Aggregate<T>
{
    fn GetUncomittedChanges(&self) -> Vec<Box<Any>> { self.changes}
    fn MarkChangesAsCommitted(&self)  { self.changes.drain(..);}
}


trait AggregateRoot
{
    fn new2() -> Self;  //should be private
    fn new(id: Uuid) -> Self;

    fn LoadsFromHistory(changes : Vec<Box<Any>> ) -> Self
         where Self: Sized
    {
        let newAgg  = AggregateRoot::new2 ();
        changes.iter().map( |e| newAgg.Apply(e) );
        newAgg.MarkChangesAsCommitted();
        newAgg
    }

    fn Apply<U: Any>(&self, arg: U) ;
    fn GetId(&self) -> Uuid;
}

目前正在尝试,但提供了 2 个参数,预计提供 1 个。

【问题讨论】:

  • 呈现的代码有问题,没有描述的错误。相反,在编译代码后,我得到的错误是“没有为类型 Self 实现特征 core::marker::Sized”和“没有名为 map 的方法”。请创建一个MCVE,最好是在Rust Playground 上编译。
  • where 子句让你看到那个错误,但它看起来不对第二个错误是用 iter() 修复的。第一个错误是你是怎么做的。我不知道该怎么做才能让它编译。这是我目前的尝试

标签: rust


【解决方案1】:

让我们从您提出问题的方式开始,希望您将来能够提出更好的问题。您得到的完整错误是:

<anon>:27:37: 27:52 error: the type of this value must be known in this context
<anon>:27             changes.iter().map( |e| newAgg.Apply(e) );
                                              ^~~~~~~~~~~~~~~

请注意,编译器错误消息会准确地向您显示哪部分代码有问题。在提出问题时包含该错误很有用。

您还包含了无关的细节。例如,GetUncomittedChangesidGetId 在您的示例中都未使用。解决问题时,您应该生成MCVE。这可以帮助您更好地理解问题,还可以帮助您查看更少的代码,这通常会导致更快的周转。


您的代码有很多问题,但让我们从第一个错误开始:

let newAgg  = AggregateRoot::new2 ();

这表示“对于任何可能的AggregateRoot,创建一个新的”。许多具体类型可以实现一个特征(这是特征的点),但编译器需要知道为给定实例分配多少空间。可能有一个结构需要 1 个字节或 200 个字节; 这个情况下需要在栈上分配多少空间?

要进步,您可以改用Self::new2。这意味着创建一个当前实现者的新实例

下一个错误是

<anon>:20:16: 20:40 error: no method named `MarkChangesAsCommitted` found for type `Self` in the current scope
<anon>:20         newAgg.MarkChangesAsCommitted();
                         ^~~~~~~~~~~~~~~~~~~~~~~~

您正在从 trait 实现中调用具体类型的方法;这根本没有任何意义。如果bool 实现了这个特性会发生什么?它没有MarkChangesAsCommitted 方法。我不知道您在这种情况下的意图,所以我将其删除。

现在你得到这个错误:

<anon>:19:9: 19:16 error: `changes` does not live long enough
<anon>:19         changes.iter().map( |e| newAgg.Apply(e) );
                  ^~~~~~~

note: reference must be valid for the static lifetime...
<anon>:17:5: 21:6 note: ...but borrowed value is only valid for the scope of parameters for function at 17:4

那是因为你的方法Apply 期望得到一个实现Any 的类型。但是,您传递的是&amp;Box&lt;Any&gt;Any 的生命周期为 'static,并且该引用不是静态的。一个直接的更改是接受对实现 Any 的类型的引用:

fn Apply<U: Any>(&self, arg: &U);

现在代码已经编译,还有一些文体问题需要修复:

  1. : 之前没有空格
  2. &gt; 后面没有空格
  3. ( 之前没有空格
  4. () 内没有空格
  5. map 不应用于副作用
  6. 函数和变量名是camel_case
  7. 大多数时候,接受 &amp;[T] 而不是 Vec&lt;T&gt; 作为函数参数。
  8. 使用“Egyptian”大括号,除非您使用where 子句。

总而言之,您的代码如下所示:

use std::any::Any;

struct Aggregate<T: AggregateRoot> {
    agg: T,
    changes: Vec<Box<Any>>
}

impl<T: AggregateRoot> Aggregate<T> {
    fn mark_changes_as_committed(&self) { }
}

trait AggregateRoot {
    fn new() -> Self;

    fn load_from_history(changes: &[Box<Any>]) -> Self
         where Self: Sized
    {
        let new_agg = Self::new();
        for change in changes { new_agg.apply(change) }
        new_agg
    }

    fn apply<U: Any>(&self, arg: &U);
}

fn main() {}

有没有办法将AggregateRoot 的具体类型限制为Aggregates 以便可以调用mark_changes

我不知道。听起来您想将mark_changes 移动到特征并强制该特征的所有实现者实现它:

trait AggregateRoot {
    fn load_from_history(changes: &[Box<Any>]) -> Self
         where Self: Sized
    {
        let new_agg = Self::new();
        for change in changes { new_agg.apply(change) }
        new_agg.mark_changes_as_committed();
        new_agg
    }

    fn mark_changes_as_committed(&self);

    // ...
}

【讨论】:

  • 有没有办法将 Aggregateroot 的具体类型限制为 Aggregates 以便可以调用标记更改?申请是我一直在寻找的。在学习一门新语言时,你会尝试很多事情。这表示“对于任何可能的 AggregateRoot,创建​​一个新的”。这样做的目的是让外部对象可以创建具体的实现并通过事件(通常是存储库)填充它,具体的 impl 将处理这些实现。调用者可以将其标记为完成,但如果不完成则会导致错误的错误。
  • @user1496062 我在线回答了您的问题。我不清楚您的评论中是否隐藏了更多问题:-)
  • 谢谢。 markchanges 专门与数据相关,它清除了基础集合。您可以从 C#/F# 示例中看到我正在尝试做的事情。因为他们有一些我还没有得到的具体实现。请注意,所有 impl 都将使用 struct Aggregate 并对其进行扩展,它们之间的联系非常紧密。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 2013-03-20
相关资源
最近更新 更多