有没有办法在另一个特征之上实现一个特征?
Is there a way to implement a trait on top of another trait?
我正在尝试创建一个基本特征来实现其他运算符特征(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`
不能为特征实现特征,只能为类型实现特征。
但是您可以为实现特定特征(特征边界)的泛型类型实现特征。
像这样:
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)
}
}
不幸的是,您只能对 您的 板条箱中定义的特征执行此操作(称为连贯性),因此您不能对 std Add
特征执行此操作,因为它已定义在 std 板条箱中,而不是在您的板条箱中。
我想你可能需要定义一些宏来做你想做的事。
问题不在于 Sized。您要查找的语法是:
impl<T: Measurement> Add for T { ... }
而不是:
impl Add for Measurement { ... }
因为 for
的右边必须是一个对象,而不是一个特征,而是一个类型参数约束到一个特征(即 T
必须是 Measurement
) 有效。
现在您的代码仍然无法编译。您将获得以下内容:
error: type parameter T
must be used as the type parameter for some
local type (e.g. MyStruct<T>
); only traits defined in the current
crate can be implemented for a type parameter [E0210]
这里的问题完全不同。我不确定它是否与问题有关,但我仍然会解释发生了什么。当您将 Add
的实现写入任何 Measurement
的 T
时,您打开了一个类型已经实现了 Add
的可能性,并且还将实现 Measurement
别处。想象一下,如果你想在 u8
上实现 Measurement
(这很愚蠢但是 可能 ):Rust 应该为 Add
选择哪个实现?原来的 std
impl 还是你的 Measurement
impl? (in-depth discussion about this issue)
现在 Rust 明确禁止 impl,如果它不是至少 1) 你自己的特征或 2) 你自己的类型("own" 正式意味着,在你正在编写你的 impl 的箱子里)。这就是为什么你可以写 impl Add for Unit
: 因为你拥有 Unit
.
最简单的解决方案是放弃并为您计划制作的每种类型独立实施添加 Unit
。假设你的 crate 定义了 Inches
和 Centimeter
,每个都有自己的 Add
impl。如果代码非常相似,并且您觉得自己已经搞砸了,请利用 macros. Here is how the std
crate does it:
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 }
)*)
}
根据建议,这是一个带有宏的工作版本:
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());
}
我正在尝试创建一个基本特征来实现其他运算符特征(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`
不能为特征实现特征,只能为类型实现特征。 但是您可以为实现特定特征(特征边界)的泛型类型实现特征。 像这样:
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)
}
}
不幸的是,您只能对 您的 板条箱中定义的特征执行此操作(称为连贯性),因此您不能对 std Add
特征执行此操作,因为它已定义在 std 板条箱中,而不是在您的板条箱中。
我想你可能需要定义一些宏来做你想做的事。
问题不在于 Sized。您要查找的语法是:
impl<T: Measurement> Add for T { ... }
而不是:
impl Add for Measurement { ... }
因为 for
的右边必须是一个对象,而不是一个特征,而是一个类型参数约束到一个特征(即 T
必须是 Measurement
) 有效。
现在您的代码仍然无法编译。您将获得以下内容:
error: type parameter
T
must be used as the type parameter for some local type (e.g.MyStruct<T>
); only traits defined in the current crate can be implemented for a type parameter [E0210]
这里的问题完全不同。我不确定它是否与问题有关,但我仍然会解释发生了什么。当您将 Add
的实现写入任何 Measurement
的 T
时,您打开了一个类型已经实现了 Add
的可能性,并且还将实现 Measurement
别处。想象一下,如果你想在 u8
上实现 Measurement
(这很愚蠢但是 可能 ):Rust 应该为 Add
选择哪个实现?原来的 std
impl 还是你的 Measurement
impl? (in-depth discussion about this issue)
现在 Rust 明确禁止 impl,如果它不是至少 1) 你自己的特征或 2) 你自己的类型("own" 正式意味着,在你正在编写你的 impl 的箱子里)。这就是为什么你可以写 impl Add for Unit
: 因为你拥有 Unit
.
最简单的解决方案是放弃并为您计划制作的每种类型独立实施添加 Unit
。假设你的 crate 定义了 Inches
和 Centimeter
,每个都有自己的 Add
impl。如果代码非常相似,并且您觉得自己已经搞砸了,请利用 macros. Here is how the std
crate does it:
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 }
)*)
}
根据建议,这是一个带有宏的工作版本:
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());
}