繁体   English   中英

我可以实现一个将信息添加到Rust中的外部类型的特征吗?

[英]Can I implement a trait which adds information to an external type in Rust?

我刚刚实现了一个简单的特性来保存struct属性的历史:

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特征(或类似的东西)添加到尚未具有history属性的东西(如u32String ),有效地处理有关变量具有哪些值的一些信息有人吗?

否。特征无法将数据成员添加到现有结构中。 实际上,只有程序员才能通过修改结构的定义来做到这一点。 包装结构或散列表是可行的方法。

不,特征只能包含行为,而不能包含数据。 但你可以制作一个结构。

如果你可以为u32实现History ,你必须无限期地保留每个 u32对象的整个历史记录,以防有一天有人决定在它上面调用.history() (另外,当你将一个u32分配给另一个时会发生什么?它的历史记录是否附带它,或新的值是否刚刚添加到列表中?)

相反,您可能希望能够标记特定的 u32对象以保留历史记录。 正如red75prime的回答所示,包装结构将起作用:

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>或任何您想要的内容,但get()方法仅在包装类型为Copy 。*您的Weight类型可能只是History<u32>的别名History<u32> 这是在操场上。

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

作为旁注,当你可以使用&[T]时,你几乎不会想要&Vec<T> ,所以我改变了history()的签名。 您可能会考虑的另一件事是返回迭代器而不是先前的值(可能是相反的顺序)而不是切片。


*从History<T>中获取T更好方法是实现Deref并编写*foo而不是foo.get()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM