我试图了解如何在Rust中实现一般特征.
虽然我已经看过很多例子,但这些例子与特定用途(例如基因组变异器)过于紧密联系,因此我能够在Rust开发过程中理解这一点.
相反,这是一个基于相当普遍的东西的简单示例 - 递增:
trait Incrementable { fn post_inc(&mut self) -> Self; fn post_inc_by(&mut self, n: usize) -> Self; } impl Incrementable for usize { fn post_inc(&mut self) -> Self { let tmp = *self; *self += 1; tmp } //"Overload" for full generalizability fn post_inc_by(&mut self, n: usize) -> Self { let tmp = *self; *self += n; tmp } } fn main() { let mut result = 0; assert!(result.post_inc() == 0); assert!(result == 1); assert!(result.post_inc_by(3) == 1); assert!(result == 4); }
上面的代码有效,但缺乏,因为如果没有编写大量的样板代码,它不能推广到所有数字类型.
在我试图概括上面的代码时,我已经开始与类型系统打斗,借用检查器或被强制执行FromPrimitive
我希望在我的通用版本中支持的每种类型的路径(有效地让我回到原点) .
您是否可以帮助我了解如何Incrementable
一般地实现,post_inc()
以及post_inc_by()
至少适用于所有整数和浮点类型,理想情况下无需为每种类型编写实现?
我希望答案能帮助我了解特征,实现,类型和相关类型如何在一个比我能够遇到的更简单的用例中协同工作.
我在Rust 1.16.0上.
@Simon Whitehead的例子很容易适应稳定的Rust:
trait Incrementable: Copy + std::ops::AddAssign{ fn one() -> Self; fn post_inc(&mut self) -> Self { self.post_inc_by(Self::one()) } fn post_inc_by(&mut self, n: Self) -> Self { let tmp = *self; *self += n; tmp } } impl Incrementable for u8 { fn one() -> Self {1} } impl Incrementable for u16 { fn one() -> Self {1} } impl Incrementable for u32 { fn one() -> Self {1} } impl Incrementable for u64 { fn one() -> Self {1} } impl Incrementable for i8 { fn one() -> Self {1} } impl Incrementable for i16 { fn one() -> Self {1} } impl Incrementable for i32 { fn one() -> Self {1} } impl Incrementable for i64 { fn one() -> Self {1} } impl Incrementable for f32 { fn one() -> Self {1.0} } impl Incrementable for f64 { fn one() -> Self {1.0} }
虽然您需要为每种类型执行实现,但每种类型都非常简单.
您还可以使用宏来隐藏重复的实现:
macro_rules! impl_Incrementable{ ($($m:ty),*) => {$( impl Incrementable for $m { fn one() -> Self { 1 as $m } })*} } impl_Incrementable!{u8, u16, u32, u64, i8, i16, i32, i64, f32, f64}