What are some general strategies for resolving trait implementations when using generics in Rust? As a contrived example, consider the following code that allows conversion from primitive types to a struct:
// External libraries
use std::fmt::Debug;
// Create some structure that we can convert from and into
#[derive(Debug)]
struct MyStruct <T> {
val : T,
}
// Convert from a value
trait ConvertFrom <T>
where
Self : Sized
{
fn from(t : T) -> Self;
}
// Convert T into a T
impl <T> ConvertFrom <T> for T {
fn from(t : T) -> Self {
t
}
}
// Convert f32 into f64
impl ConvertFrom <f32> for f64 {
fn from(t : f32) -> Self {
t as f64
}
}
// Convert T into a MyStruct <U>
impl <T,U> ConvertFrom <T> for MyStruct <U>
where
U : ConvertFrom <T>
{
fn from(t : T) -> Self {
MyStruct{ val : ConvertFrom::<T>::from(t) }
}
}
// Test our conversion
fn foo01 <T> () -> ()
where
T : ConvertFrom <f32> + Debug
{
let y01 : T = ConvertFrom::<f32>::from(1.2_f32);
println!("{:?}",y01);
}
fn main() {
foo01::<MyStruct<f32>>();
foo01::<f64>();
}
This gives the compiler error:
error[E0119]: conflicting implementations of trait `ConvertFrom<MyStruct<_>>` for type `MyStruct<_>`:
--> src/test03.rs:33:1
|
19 | impl <T> ConvertFrom <T> for T {
| ------------------------------ first implementation here
...
33 | / impl <T,U> ConvertFrom <T> for MyStruct <U>
34 | | where
35 | | U : ConvertFrom <T>
36 | | {
... |
39 | | }
40 | | }
| |_^ conflicting implementation for `MyStruct<_>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.
error: Could not compile `rust_from_to`
This makes sense, there's an ambiguity between the identity conversion from T->T
and from T->MyStruct <U>
since T
could be something like MyStruct<f32>
and U
could be f32
. What's not clear to me is how to resolve it and rustc --explain E0119
did not give great hints. At issue is that I'd like to have a conversion function that converts T
into MyStruct <U>
whenever T
converts to U
. I can make this work if T=U
with the trait:
// Convert T into a MyStruct <T>
impl <T> ConvertFrom <T> for MyStruct <T> {
fn from(t : T) -> Self {
MyStruct{ val : t }
}
}
but this is less general than I'd like. Is there a general strategy for constructing such traits or functions?