[英]Problem implementing a trait to multiple types
As a practice exercise, I'm trying to create a temperature unit library.作为练习,我正在尝试创建一个温度单位库。
Currently, the following code won't compile and the error message is unclear to me.目前,以下代码无法编译,并且我不清楚错误消息。 The problem seems to be a type conflict.
问题似乎是类型冲突。
type Fahrenheit = f64;
type Celcius = f64;
type Kelvin = f64;
trait TemperatureUnit {
fn to_kelvin(&self) -> Kelvin;
}
impl TemperatureUnit for Fahrenheit {
fn to_kelvin(&self) -> Kelvin {
(*self + 459.67) * 5/9
}
}
impl TemperatureUnit for Celcius {
fn to_kelvin(&self) -> Kelvin {
*self + 273.15
}
}
impl TemperatureUnit for Kelvin {
fn to_kelvin(&self) -> Kelvin {
*self
}
}
Errors:错误:
error[E0119]: conflicting implementations of trait `TemperatureUnit` for type `f64`
--> src/lib.rs:18:1
|
12 | impl TemperatureUnit for Fahrenheit {
| ----------------------------------- first implementation here
...
18 | impl TemperatureUnit for Celcius {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `f64`
error[E0119]: conflicting implementations of trait `TemperatureUnit` for type `f64`
--> src/lib.rs:24:1
|
12 | impl TemperatureUnit for Fahrenheit {
| ----------------------------------- first implementation here
...
24 | impl TemperatureUnit for Kelvin {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `f64`
I'm new to Rust, so maybe this is not the proper methodology to achieve a compiler-enforced type-safe unit conversion.我是 Rust 的新手,所以也许这不是实现编译器强制类型安全单元转换的正确方法。
When you write type
, you're making a type alias, not a new type.当你写
type
时,你是在创建一个类型别名,而不是一个新类型。 It's like when you use typedef
in C++, for instance.例如,就像在 C++ 中使用
typedef
一样。
type Fahrenheit = f64;
This literally says "when I say 'Fahrenheit', pretend I said f64
instead".这字面意思是“当我说'华氏'时,假装我说的
f64
”。 Not a new type, not a distinct structure, literally the same.不是一种新的类型,不是一种独特的结构,字面上是一样的。 So you just implemented
TemperatureUnit for f64
three times.因此,您刚刚
TemperatureUnit for f64
。
If you want to wrap f64
in a custom type under your control, you're looking for the newtype pattern .如果您想将
f64
包装在您控制下的自定义类型中,您正在寻找newtype pattern 。
pub struct Fahrenheit(pub f64);
Now Fahrenheit
is a distinct structure that happens to be isomorphic to f64
.现在
Fahrenheit
是一个独特的结构,恰好与f64
同构。 You can go from f64
to Fahrenheit
with the Fahrenheit(x)
constructor, and you can go back with the my_fahrenheit.0
projection.您可以使用
Fahrenheit(x)
构造函数从f64
转到Fahrenheit
,也可以使用my_fahrenheit.0
投影返回。 You can also name the projection if you prefer.如果您愿意,也可以命名投影。
pub struct Fahrenheit { pub float_repr: f64 };
Rust will almost certainly compile this internally to an actual f64
. Rust 几乎肯定会在内部将其编译为实际的
f64
。 Structs with only one field will generally have no overhead.只有一个字段的结构通常没有开销。 But we can actually guarantee this with
repr(transparent)
但我们实际上可以用
repr(transparent)
来保证这一点
#[repr(transparent)]
pub struct Fahrenheit(pub f64);
This guarantees that, at runtime, Fahrenheit
and f64
have the same representation (even to the extent that transmute
is defined between them), while at compile-time they're distinct types.这保证了在运行时,
Fahrenheit
和f64
具有相同的表示形式(即使在它们之间定义了transmute
的程度),而在编译时它们是不同的类型。
The only thing left to decide is what traits you want your new type to implement.唯一需要决定的是您希望新类型实现哪些特征。 It will inherit nothing from
f64
by default, so you'll likely have a massive derive(...)
clause right before the declaration including Eq
, Ord
, Clone
, Copy
, etc. (non-exhaustive list; you know your use case better than I do)默认情况下,它不会从
f64
继承任何内容,因此您可能会在声明之前有一个巨大的 derived derive(...)
子句,包括Eq
、 Ord
、 Clone
、 Copy
等(非详尽列表;您知道您的用例比我好)
The problem here is that type
just aliases a type, it doesn't create a new one.这里的问题是
type
只是一个类型的别名,它不会创建一个新的类型。 Rust is complaining because those three impl
blocks are trying to implement TemperatureUnit
on the same type three times. Rust 抱怨是因为这三个
impl
块试图在同一类型上实现TemperatureUnit
三次。
Instead, you should declare new types.相反,您应该声明新类型。 The example below uses
struct
.下面的示例使用
struct
。
struct Fahrenheit(f64);
struct Celcius(f64);
struct Kelvin(f64);
trait TemperatureUnit {
fn to_kelvin(&self) -> Kelvin;
}
impl TemperatureUnit for Fahrenheit {
fn to_kelvin(&self) -> Kelvin {
Kelvin((self.0 + 459.67) * 5.0/9.0)
}
}
impl TemperatureUnit for Celcius {
fn to_kelvin(&self) -> Kelvin {
Kelvin(self.0 + 273.15)
}
}
impl TemperatureUnit for Kelvin {
fn to_kelvin(&self) -> Kelvin {
Kelvin(self.0)
}
}
fn main()
{
println!("Hey");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.