我想创建一个基本特征,将实现其他运营商的特征(Add,Subtract,Multiply,Divide,等...)我.
这无法编译,它看起来像一个发布Sized,但即使Measurement设置为要求Sized它不起作用.这甚至可能吗?
use std::ops::Add;
#[derive(Copy, Clone, Debug)]
struct Unit {
value: f64,
}
impl Unit {
fn new(value: f64) -> Unit {
Unit { value: value }
}
}
trait Measurement: Sized {
fn get_value(&self) -> f64;
fn from_value(value: f64) -> Self;
}
impl Measurement for Unit {
fn get_value(&self) -> f64 {
self.value
}
fn from_value(value: f64) -> Self {
Unit::new(value)
}
}
// This explicit implementation works
/*
impl Add for Unit {
type Output = Unit;
fn add(self, rhs: Unit) -> Unit {
let a = self.get_value();
let b = rhs.get_value();
Unit::from_value(a + b)
}
}
*/
// This trait implementation does not
impl Add for Measurement {
type Output = Self;
fn add(self, rhs: Self) -> Self {
let a = self.get_value();
let b = rhs.get_value();
Self::from_value(a + b)
}
}
fn main() {
let a = Unit::new(1.5);
let b = Unit::new(2.0);
let c = a + b;
println!("{}", c.get_value());
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
error[E0277]: the trait bound `Measurement + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:42:6
|
42 | impl Add for Measurement {
| ^^^ `Measurement + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Measurement + 'static`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:42:6
|
42 | impl Add for Measurement {
| ^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:43:5
|
43 | type Output = Self;
| ^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
error[E0038]: the trait `Measurement` cannot be made into an object
--> src/main.rs:45:5
|
45 | fn add(self, rhs: Self) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Measurement` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
Run Code Online (Sandbox Code Playgroud)
问题不在于大小.您正在寻找的语法是:
impl<T: Measurement> Add for T { ... }
Run Code Online (Sandbox Code Playgroud)
代替:
impl Add for Measurement { ... }
Run Code Online (Sandbox Code Playgroud)
因为for必须是对象的右侧而不是特征,所以限制为特征的类型参数(即T必需的Measurement)是有效的.
现在你的代码仍然无法编译.您将获得以下内容:
error:type参数
T必须用作某些本地类型的类型参数(例如MyStruct<T>); 只有当前包中定义的特征才能为类型参数实现[E0210]
这里的问题完全不同.我不确定它是否与这个问题有关,但我仍然会解释发生了什么.当你写一个IMPL Add任何T这是Measurement,你打开一个类型就已经实现的可能性Add就其本身而言,也将实现Measurement在其他地方.试想一下,如果你想实现Measurement的u8(这是愚蠢的,但可能):这应该IMPL选择生锈了Add?最初的stdimpl还是你的Measurementimpl?(关于这个问题的深入讨论)
现在Rust显然禁止impl如果它不是至少1)你自己的特性或2)你自己的类型("拥有"正式意味着,在你正在写你的impl的箱子里).这就是为什么你可以写impl Add for Unit:因为你拥有Unit.
最简单的解决方案是为您计划制作的每种类型单独放弃并实施Add Unit.说你的箱子定义Inches和Centimeter,每个人将有自己的AddIMPL.如果代码侮辱性地相似,并且你觉得你破坏了DRY,那就利用宏.下面是该怎么std箱子做它:
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
forward_ref_binop! { impl Add, add for $t, $t }
)*)
}
Run Code Online (Sandbox Code Playgroud)