我正在尝试创建一个基本特征,它将为我实现其他操作员特征(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());
}
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`
答案 0 :(得分:7)
问题不在于大小。您正在寻找的语法是:
impl<T: Measurement> Add for T { ... }
而不是:
impl Add for Measurement { ... }
因为for
的右侧必须是对象而不是特征,但是类型参数必须是特性(即T
必须是Measurement
)是有效的。
现在你的代码仍然无法编译。您将获得以下内容:
错误:类型参数
T
必须用作某些类型参数 本地类型(例如MyStruct<T>
);只有当前定义的特征 crate可以用于类型参数[E0210]
这里的问题完全不同。我不确定它是否与问题有关,但我仍然会解释发生了什么。当您将Add
的impl写入T
的任何Measurement
时,您可以打开类型已经自己实现Add
的可能性,并且还会实现{ {1}}其他地方。想象一下,如果你想在Measurement
上实现Measurement
(这很愚蠢但可能):Rust应该为u8
选择哪个impl?最初的Add
impl或您的std
impl? (in-depth discussion about this issue)
现在Rust显然禁止impl如果它不是至少1)你自己的特性或2)你自己的类型(其中&#34;拥有&#34;正式意味着,在箱子里你正在写你的IMPL)。这就是为什么你可以写Measurement
:因为你拥有impl Add for Unit
。
最简单的解决方案是为您计划制作Unit
的每种类型单独放弃并实施添加。说你的箱子定义Unit
和Inches
,每个人都有自己的Centimeter
impl。如果代码侮辱性地相似,并且你觉得你破坏了干,请利用macros。这是how the std
crate does it:
Add
答案 1 :(得分:0)
您无法为特征实现特征,只能为类型实现特征。 但是,您可以为实现某些特征(特征边界)的泛型类型实现特征。 像这样:
impl<T : Measurement> Add<T> for T {
type Output = T;
fn add(self, rhs: Self) -> T {
let a = self.get_value();
let b = rhs.get_value();
T::from_value(a + b)
}
}
不幸的是,你只能对你的 crate中定义的特征(它叫做coherence)这样做,所以你不能为std Add
特征做到这一点,因为它是在std crate中定义的,不在你的身上。
我认为你可能需要定义一些宏来做你想做的事。
答案 2 :(得分:0)
这是一个带有宏的工作版本,如建议的那样:
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)
}
}
macro_rules! add_impl {
($($t:ty)*) => ($(
impl Add for $t {
type Output = $t;
fn add(self, other: $t) -> $t {
let a = self.get_value();
let b = other.get_value();
let r = a + b;
Self::from_value(r)
}
}
)*)
}
add_impl! { Unit }
fn main() {
let a = Unit::new(1.5);
let b = Unit::new(2.0);
let c = a + b;
println!("{}", c.get_value());
}