尝试在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个供应。
答案 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) );
^~~~~~~~~~~~~~~
请注意,编译器错误消息会准确显示哪个代码位出错。在提问时包含该错误很有用。
你还包括无关的细节。例如,GetUncomittedChanges
,id
和GetId
在您的示例中都未使用。解决问题时,您应该生成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);
现在代码编译了,需要解决许多风格问题:
:
>
(
()
map
不应用于副作用camel_case
&[T]
而不是Vec<T>
作为函数参数。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);
// ...
}