2017-11-18 39 views
3

我只是实现了一个简单的特质,以保持一个结构属性的历史:我可以实现在Rust中向外部类型添加信息的特性吗?

fn main() { 
    let mut weight = Weight::new(2); 
    weight.set(3); 
    weight.set(5); 
    println!("Current weight: {}. History: {:?}", weight.value, weight.history); 
} 

trait History<T: Copy> { 
    fn set(&mut self, value: T); 
    fn history(&self) -> &Vec<T>; 
} 

impl History<u32> for Weight { 
    fn set(&mut self, value: u32) { 
     self.history.push(self.value); 
     self.value = value; 
    } 
    fn history(&self) -> &Vec<u32> { 
     &self.history 
    } 
} 

pub struct Weight { 
    value: u32, 
    history: Vec<u32>, 
} 

impl Weight { 
    fn new(value: u32) -> Weight { 
     Weight { 
      value, 
      history: Vec::new(), 
     } 
    } 
} 

我不认为这是可能的,但你可以在History特征(或等价的东西)添加到一些东西,没有按” t已经有一个history属性(如u32String),有效地加强了有关变量采用哪些值的一些信息?

回答

3

编号特征不能将数据成员添加到现有结构。实际上,只有程序员可以通过修改结构的定义来做到这一点。包装结构或散列表是要走的路。

2

不,性状只能包含行为,而不能包含数据。但是你可以创建一个结构体。

如果你能实现Historyu32,你必须保持整个历史上的每u32对象无限,万一有一天,有人决定把它.history()。 (另外,就当你将一个u32到另一个发生什么呢?难道它的历史随之而来,或做新的价值只是被添加到列表中?)

相反,你可能希望能够标记特定u32保留历史记录的对象。一个包装结构,为red75prime's answer建议,将工作:

mod hist { 
    use std::mem; 

    pub struct History<T> { 
     value: T, 
     history: Vec<T>, 
    } 

    impl<T> History<T> { 
     pub fn new(value: T) -> Self { 
      History { 
       value, 
       history: Vec::new(), 
      } 
     } 

     pub fn set(&mut self, value: T) { 
      self.history.push(mem::replace(&mut self.value, value)); 
     } 

     pub fn get(&self) -> T 
     where 
      T: Copy, 
     { 
      self.value 
     } 

     pub fn history(&self) -> &[T] { 
      &self.history 
     } 
    } 
} 

它是通用的,所以你可以有一个History<u32>History<String>或任何你想要的,但是当包裹类型为Copyget()方法才会被执行*。您的Weight类型可能只是History<u32>的别名。 Here it is in the playground.

将此代码包装到模块中是保持抽象的必要部分。这意味着你不能写weight.value,你必须致电weight.get()。如果value标记为pub,则可以直接指定weight.value(绕过set),然后history将不准确。

作为一个侧面说明,你almost never&Vec<T>时可以使用&[T],所以我改变了history()签名。你可能会考虑的另一件事是将迭代器返回到先前的值(可能是相反的顺序)而不是片。


*获得THistory<T>的更好的办法是实施Deref,写*foo而不是foo.get()

相关问题