特征动态调度中的静态方法

时间:2015-10-23 05:03:31

标签: rust

尝试在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个供应。

1 个答案:

答案 0 :(得分:2)

让我们先从您提出问题的问题开始,希望您将来可以提出更好的问题。你得到的完整错误是:

<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();
                         ^~~~~~~~~~~~~~~~~~~~~~~~

您正在从特征实现中调用具体类型的方法;这根本没有任何意义。如果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的类型。但是,您传递的是&Box<Any>Any的生命周期范围为'static,该引用不是静态的。一个简单的改变是接受对实现Any的类型的引用:

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

现在代码编译了,需要解决许多风格问题:

  1. :
  2. 之前没有空格
  3. >
  4. 之后没有空格
  5. (
  6. 之前没有空格
  7. ()
  8. 内没有空格
  9. map不应用于副作用
  10. 函数和变量名称为camel_case
  11. 大部分时间,接受&[T]而不是Vec<T>作为函数参数。
  12. 使用“埃及”大括号,除非您使用where条款。
  13. 总之,您的代码如下:

    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);
    
        // ...
    }