Beginner Query: implementing traits for generic structs

Okay. I like the idea of rust, but I've not found the experience of learning rust to be especially user-friendly. I'm working on a computer vision application, and I'd like to build a simple math library to get myself started. My first crack at the implementation is starting with the lowly 3D vector.

struct Vec3<T : Add + Copy> {
    x: T,
    y: T,
    z: T
}

My thought is that any type that should live in the vector struct needs to support addition. The next step is to define addition on my Vec3, like so:

impl<T> Add for Vec3<T> where T:Add + Copy {
    type Output = Vec3<T>;

    fn add(self, rhs: Vec3<T>) -> Vec3<T> {
    	Vec3<T:Add+Copy>{x: (self.x + rhs.x), y: (self.y + rhs.y), z: (self.z + rhs.z)}
    }
}

This doesn't work! rustc tells me that the problem is as follows:

error: expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:`
geometry/three/mod.rs:13     	Point<T:Add+Copy>{x: (self.x + rhs.x), y: (self.y + rhs.y), z: (self.z + rhs.z)}

It's quite easy to modify things to get other errors... but it's not clear to me how this example should be written to make the compiler happy. I would appreciate the wisdom of those who have trod this path before me.

You don't specify type parameters when constructing a struct:

Vec3 {
    x: (self.x + rhs.x),
    y: (self.y + rhs.y),
    z: (self.z + rhs.z),
}

I appreciate the tip, but removing the type parameters just leads me to new errors. This time of the general form:

error: mismatched types:
 expected `Vec3<T>`,
    found `Vec3<<T as core::ops::Add>::Output>`
(expected type parameter,
    found associated type) [E0308]
Vec3{x: (self.x + rhs.x), y: (self.y + rhs.y), z: (self.z + rhs.z)}

error: the trait `core::marker::Copy` is not implemented for the type `<T as core::ops::Add>::Output` [E0277]
error: the trait `core::ops::Add` is not implemented for the type `<T as core::ops::Add>::Output` [E0277]

I'm assuming the main problem is the first one, that instead of "T", the compiler found "T as core::ops::Add>::Output"

It's not clear to me why this is happening or what I'm supposed to be doing differently.

Fundamentally, the issue is that the output type of addition isn't directly connected to the type of the operands; addition is allowed to return any type that makes sense (for example, you could say that adding a real number and an imaginary number returns a complex number).

There are a couple of different ways you can go; make the implementation a bit more flexible:

impl<T> Add for Vec3<T> where T:Add + Copy, T::Output:Add+Copy {
    type Output = Vec3<T::Output>;

    fn add(self, rhs: Vec3<T>) -> Vec3<T::Output> {
        Vec3 {
            x: (self.x + rhs.x),
            y: (self.y + rhs.y),
            z: (self.z + rhs.z),
        }
    }
}

or lock it down a bit more:

impl<T> Add for Vec3<T> where T:Add<Output=T> + Copy {
    type Output = Vec3<T>;

    fn add(self, rhs: Vec3<T>) -> Vec3<T> {
        Vec3 {
            x: (self.x + rhs.x),
            y: (self.y + rhs.y),
            z: (self.z + rhs.z),
        }
    }
}

Thank you very much! This is quite helpful. I can't say that I completely understand the syntax/semantics here, however.

To wit, let's say I'd like to define my geometry so that I have points and vectors, defined as their own structs, but in reality they have the same layout:

struct Vec3<T : Add + Copy> {
    x: T,
    y: T,
    z: T
}

struct Pnt3<T : Add + Copy> {
    x: T,
    y: T,
    z: T
}

I'd now like to define addition between two vectors, and between a point and a vector, as follows:

Point = Vector + Point
Point = Point + Vector
Vector = Vector + Vector
plus scalar multiplication for vectors, etc.

In my naiveté, I would assume that I can do something like the following, and simply add another impl block:

impl<T> Add for Vec3<T> where T:Add<Output=T> + Copy {
    type Output = Pnt3<T>;

    fn add(self, rhs: Pnt3<T>) -> Pnt3<T> {
        Pnt3 {
            x: (self.x + rhs.x),
            y: (self.y + rhs.y),
            z: (self.z + rhs.z),
        }
    }
}

In my mind this is saying: define addition between the point and the vector, where each is parameterized over the same type, and return a new point. The compiler does not agree with my mental model and complains thusly:

error: conflicting implementations for trait `core::ops::Add` [E0119]

So I can see why they would conflict... but I'm pretty sure this is possible, since what I intend ought not to conflict. A vector plus a point is not the same as a vector plus a vector. So what is the correct syntax here?

I apologize again for my ignorance.

Recall the Add trait definition:

pub trait Add<RHS = Self>

When you write just

impl<T> Add for Vec3<T>

you're implementing Add<Self> and Self is Vec3<T> -- "Something = Vector + Vector".

The "Vector + Point" case would be Add<Pnt3<T>>.

Okay, that actually makes perfect sense.

Hopefully I'll make it further along now before needing to ask another simple question.

Thanks again!

Okay, I've considered making another topic for this, but it does fit the overarching theme here...
Is there any way to group a set of traits together in a clean fashion? Something along the lines of:

trait VecNum: Add + Mul + Sub + Neg + Copy{

}

struct Vec3<T : VecNum> {
    x: T,
    y: T,
    z: T
}

This would avoid having a preponderance of trait bounds on my vector parameter for each trait I implement on the vector/points.

The non-stdlib num crate has such a trait: http://doc.rust-lang.org/num/num/traits/trait.Num.html