我应该如何在没有代码重复的情况下实现对于& MyType和& mut MyType?

时间:2018-04-23 15:36:19

标签: rust

这是一个玩具示例:

#[derive(Debug)]
struct Int {
    v: i32,
}

#[derive(Debug)]
struct Double {
    v: f64,
}

impl Into<Double> for Int {
    fn into(self) -> Double {
        Double {
            v: f64::from(self.v),
        }
    }
}

这很有效,但实际上我想为Into<Double>&Int实施&mut Int。这不起作用:

impl<T> Into<Double> for T
where
    T: AsRef<Int>,
{
    fn into(self) -> Double {
        Double {
            v: f64::from(self.as_ref().v),
        }
    }
}

因为我的箱子中未定义trait Into

error[E0119]: conflicting implementations of trait `std::convert::Into<Double>`:
  --> src/main.rs:19:1
   |
19 | / impl<T> Into<Double> for T
20 | | where
21 | |     T: AsRef<Int>,
22 | | {
...  |
27 | |     }
28 | | }
   | |_^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T, U> std::convert::Into<U> for T
             where U: std::convert::From<T>;

error[E0210]: 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
  --> src/main.rs:19:1
   |
19 | / impl<T> Into<Double> for T
20 | | where
21 | |     T: AsRef<Int>,
22 | | {
...  |
27 | |     }
28 | | }
   | |_^

我应该如何为Into<Double>&Int实施&mut Int, 没有代码重复,如:

impl<'a> Into<Double> for &'a Int {
impl<'a> Into<Double> for &'a mut Int {

2 个答案:

答案 0 :(得分:6)

您可以通过实施From代替其朋友Into来实现您的目标:

impl<T> From<T> for Double
where
    T: AsRef<Int>,
{
    fn from(i: T) -> Self {
        Double {
            v: f64::from(i.as_ref().v),
        }
    }
}

这样我们就可以避免为孤立规则不允许的泛型参数(for T部分)实现特征。 FromIntothis awesome blanket impl

链接在一起
impl<T, U> Into<U> for T 
where
    U: From<T>, 

然而,AsRef不是你在这里寻找的特质(我认为)。 Borrow可能更适合您的情况:

impl<T> From<T> for Double
where
    T: Borrow<Int>,
{
    fn from(i: T) -> Self {
        Double {
            v: f64::from(i.borrow().v),
        }
    }
}

这样,Int&Int&mut Int就可以进行转换:

fn foo<T: Into<Double>>(_: T) {}

foo(Int { v: 3 });
foo(&Int { v: 3 });
foo(&mut Int { v: 3 });

另见:

答案 1 :(得分:1)

Lukas的答案是你应该如何实现这一点;我想补充一点,Into<T>的这种限制也可以使用包装类型解决,如docs for the related error, E0210所述:

  

要解决此问题,可以使用本地类型MyType

覆盖它
struct MyType<T>(T);

impl<T> ForeignTrait for MyType<T> { } // Ok

话虽如此,根据您的需求,您仍应使用Borrow代替AsRef

#[derive(Debug)]
struct Wrap<T: Borrow<Int>>(T);

impl<T> Into<Double> for Wrap<T>
where
    T: Borrow<Int>,
{
    fn into(self) -> Double {
        Double {
            v: f64::from(self.0.borrow().v),
        }
    }
}

fn main() {
    let i = Int { v: 0 };
    let d: Double = Wrap(i).into(); // or Wrap(&i) or Wrap(&mut i)
}