4

I'm learning rust and I can't understand why the following code gives an error.

use std::ops::Mul;
use std::ops::Add;

struct Vec2<T>
{
    x: T,
    y: T,
}

impl<T: Mul + Add> Vec2<T> {
    fn magnitude_squared(&self) -> T {
        self.x * self.x + self.y * self.y // error here
    }
}

fn main() {
    let x = Vec2 { x: 1f32, y: 1f32 };
    println!("{}", x.magnitude_squared());
}

Error message (doesn't make much sense to me unless multiplication of two floats produces some 'non-addable' type):

src\main.rs(14,9): error E0369: binary operation + cannot be applied to type <T as std::ops::Mul>::Output
help: run rustc --explain E0369 to see a detailed explanation
note: an implementation of std::ops::Add might be missing for <T as std::ops::Mul>::Output

Rust compiler rustc 1.11.0 (9b21dcd6a 2016-08-15)
The code is similar to this example. What's the difference that makes my code wrong?

1 Answers1

4

The error message tells you what to do: you need to add an Add implementation for <T as Mul>::Output.

You can do so by adding a trait bound on your impl as such:

use std::ops::Mul;
use std::ops::Add;

struct Vec2<T: Copy>
{
    x: T,
    y: T,
}

impl<T> Vec2<T>
    where T: Copy + Mul,
          <T as Mul>::Output: Add<Output=T>
{
    fn magnitude_squared(&self) -> T {
        self.x * self.x + self.y * self.y
    }
}

fn main() {
    let x = Vec2 { x: 1f32, y: 1f32 };
    println!("{}", x.magnitude_squared());
}

The Copy was added to simplify this answer.

antoyo
  • 11,097
  • 7
  • 51
  • 82
  • Am I right in thinking that in your solution, `T*T` could be a completely different type `M`, as long as adding two `M` together gives a `T` again? – Chris Emerson Aug 26 '16 at 15:48
  • @ChrisEmerson: yes, you are right. – antoyo Aug 26 '16 at 15:56
  • Is it correct to say that a rust compiler does type checking before substitution, so it is necessary to specify traits for trait types explicitly?(I hope my wording makes sense). –  Aug 26 '16 at 16:12
  • 1
    @DmitryKuznetsov Yes, unlike C++, Rust requires that we specify the traits over generic types to use the methods from these traits in a generic function. – antoyo Aug 26 '16 at 17:23