[英]Using a generic in a struct and implementing via a trait
I have struct defined like this我有这样定义的结构
struct Shape<T> {
line_one: T,
line_two: T,
}
I am trying to create a simple trait and implementation that takes this struct to calculate some simple math.我正在尝试创建一个简单的特征和实现,它使用这个结构来计算一些简单的数学。
My trait and impls look like this我的 trait 和 impls 看起来像这样
trait Calculate<T: Mul<Output = T>> {
fn calc(&self, Shape: T) -> T;
}
impl<T> Calculate<T> for Shape<T> {
fn calc(&self, Shape: T) -> T {
self.line_one * 2 + self.line_two * 2
}
}
impl Calculate<i32> {
fn calc(&self) -> i32 {
self.line_one * 2 + self.line_two * 2
}
}
fn calc_fn<T: Calculate<i32>>(calculate: T) {
calculate.calc();
}
When I put this into the Rust playground, the compile fails as Mul
is not implemented in the impl Calculate<T>
.当我把它放到 Rust 的操场上时,编译失败,因为
Mul
没有在impl Calculate<T>
。 However, if I change <T>
to <T: Mul<Output = T>>
, I get the error that但是,如果我将
<T>
更改为<T: Mul<Output = T>>
,则会出现错误
<anon>:14:21: 14:22 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `:`
<anon>:14 impl <T> Calculate<T: Mul<Output = T>> for Shape<T>
I'm at a loss as how to implement Mul
for T
in impl Calculate<T>
.我不知道如何在
impl Calculate<T>
为T
实现Mul
。
What I'm trying to achieve is code that I can send either a f32
or i32
in without needing to create two different impl definitions so can just pass in T
.我想要实现的是我可以发送
f32
或i32
,而无需创建两个不同的 impl 定义,因此只需传入T
。
This syntax is incorrect:此语法不正确:
impl<T> Calculate<T: Mul<Output = T>> for Shape<T>
you want你要
impl<T: Mul<Output = T>> Calculate<T> for Shape<T>
I'd almost always recommend using where
clause instead;我几乎总是建议使用
where
子句; I think it reads better and might have helped prevent this case:我认为它读起来更好,可能有助于防止这种情况:
impl<T> Calculate<T> for Shape<T>
where T: Mul<Output = T>,
This just unlocks more errors.这只会解锁更多错误。 You are trying to multiply by
2
, an integral variable that hasn't been fully nailed down yet — is it a u8
?您正在尝试乘以
2
,这是一个尚未完全确定的整数变量 - 是u8
吗? is it an i32
?是
i32
吗? The restrictions don't say that T
can be multiplied by a 2
.限制并不是说
T
可以乘以2
。 Additionally, you try to add values together, but there's no guarantee that you can add the type T
.此外,您尝试将值添加在一起,但不能保证您可以添加类型
T
。
The impl Calculate<i32>
and calc_fn
blocks don't really make sense; impl Calculate<i32>
和calc_fn
块没有意义; it's unlikely you want to implement functions for the trait and you don't supply a Shape
in the latter.您不太可能想要为特征实现函数,并且您不会在后者中提供
Shape
。 The trait also doesn't use the Shape: T
parameter (and Rust uses snake_case
variable names anyway).该 trait 也不使用
Shape: T
参数(并且 Rust 无论如何都使用snake_case
变量名)。
What I'm trying to achieve is code that I can send either a
f32
ori32
in without needing to create two different impl definitions so can just pass inT
.我想要实现的是我可以发送
f32
或i32
,而无需创建两个不同的 impl 定义,因此只需传入T
。
In this case, it'd probably be way easier:在这种情况下,它可能会更容易:
trait Calculate<T> {
fn calc(&self) -> T;
}
impl Calculate<i32> for Shape<i32> {
fn calc(&self) -> i32 {
self.line_one * 2 + self.line_two * 2
}
}
impl Calculate<f32> for Shape<f32> {
fn calc(&self) -> f32 {
self.line_one * 2.0 + self.line_two * 2.0
}
}
Note that these are not equivalent!请注意,这些不是等价的! The
f64
has floating point literals ( 2.0
) not integral ( 2
). f64
具有浮点文字( 2.0
)而不是整数( 2
)。
If you must have a generic, you are going to need to convert the literal 2
to the type T
or add a restriction that T can be multiplied by some known size.如果您必须有一个泛型,您将需要将文字
2
转换为类型T
或添加一个限制,即 T 可以乘以某个已知大小。 Unfortunately, f64
cannot by multiplied by any integral value without casting.不幸的是,
f64
不能在没有强制转换的情况下乘以任何整数值。
The FromPrimitive
trait from the num crate is key here.来自 num crate 的
FromPrimitive
特性是这里的关键。 Making the types Copy
also makes the implementation easier.使类型
Copy
也使实现更容易。
extern crate num;
use std::ops::{Add, Mul};
use num::FromPrimitive;
struct Shape<T> {
line_one: T,
line_two: T,
}
trait Calculate<T> {
fn calc(&self) -> T;
}
impl<T> Calculate<T> for Shape<T>
where T: Copy + FromPrimitive + Add<Output = T> + Mul<Output = T>,
{
fn calc(&self) -> T {
let two = T::from_u8(2).expect("Unable to create a value of two");
self.line_one * two + self.line_two * two
}
}
fn main() {
let s1 = Shape { line_one: 2, line_two: 3 };
let s2 = Shape { line_one: 2.0, line_two: 3.0 };
println!("{}", s1.calc());
println!("{}", s2.calc());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.