7

I have a struct Vec3<T>, how can I implement the following method ?

impl<T: num::Num + num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (1.0 / (*self % *self).sqrt())
    }
}

error: mismatched types: expected _, found T (expected floating-point variable, found type parameter)

Type of 1.0 is _ while type of (*self % *self).sqrt() is T. And it seems it can't divide a _ by a T.

I tried various casting for 1.0 :

*self * ((1.0 as T) / (*self % *self).sqrt())

error: non-scalar cast: _ as T

*self * (1.0.div((*self % *self).sqrt()))

error: mismatched types: expected &_, found T (expected &-ptr, found type parameter)

What is the sleekest way to implement this method ?

Edit 1: As requested, here is my full code :

use std::num::Float;

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

impl<T> Vec3<T> {
    pub fn new(x: T, y: T, z: T) -> Vec3<T> {
        Vec3 { x: x, y: y, z: z }
    }
}

impl<T: Float> Add<T, Vec3<T>> for Vec3<T> {
    fn add(&self, rhs: &T) -> Vec3<T> {
        Vec3 { x: self.x + *rhs, y: self.y + *rhs, z: self.z + *rhs }
    }
}

impl<T: Float> Add<Vec3<T>, Vec3<T>> for 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 }
    }
}

impl<T: Float> Mul<T, Vec3<T>> for Vec3<T> {
    fn mul(&self, rhs: &T) -> Vec3<T> {
        Vec3 { x: self.x * *rhs, y: self.y * *rhs, z: self.z * *rhs }
    }
}

// x % y : dot-product
impl<T: Float> Rem<Vec3<T>, T> for Vec3<T> {
    fn rem(&self, rhs: &Vec3<T>) -> T {
        self.x + rhs.x * self.y + rhs.y * self.z + rhs.z
    }
}

// x ^ y : cross-product
impl<T: Float> BitXor<Vec3<T>, Vec3<T>> for Vec3<T> {
    fn bitxor(&self, rhs: &Vec3<T>) -> Vec3<T> {
        Vec3 { x: self.y * rhs.z - self.z * rhs.y,
               y: self.z * rhs.x - self.x * rhs.z,
               z: self.x * rhs.y - self.y * rhs.x }
    }
}

// !x : Norm
impl Not<Vec3<f32>> for Vec3<f32> {
    fn not(&self) -> Vec3<f32> {
        *self * (1.0f32 / (*self % *self).sqrt())
    }
}

impl Not<Vec3<f64>> for Vec3<f64> {
    fn not(&self) -> Vec3<f64> {
        *self * (1.0f64 / (*self % *self).sqrt())
    }
}

I would have used Num instead of Float to be able to have integer vectors, but since it's deprecated, I think the better option is to use macro to duplicate code for all types. Here I duplicated Not for f32 and f64

1 Answer 1

4

Literals can only be of primitive types. You can't cast a literal to some generic type.

For constants like 1.0 you can use methods like Float::one(), so your specific example could be rewritten as

impl<T: num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (num::Float::one() / (*self % *self).sqrt())
    }
}

(note that I removed Num bound because it is deprecated and in this case it is entirely superseded by Float)

To convert arbitrary values to instances of some specific Float type you can use NumCast::from() method:

let x: T = num::NumCast::from(3.14f64);

BTW, you may find this accepted RFC interesting.

Update

It is likely that you won't be able to implement Float for your structure because it has a lot of methods specific to bare floats, like mantissa size. I guess you will have to add methods like one() and zero() and probably casts from numbers yourself. Then you will be able to write

impl<T: num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (Vec3::one() / (*self % *self).sqrt())
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, but I have this error now : the type of this value must be known in this context
As I understand it, for now, generics are very limited, and it's not going to be better by deleting std::num::Num
@AurélienFusil-Delahaye, could you please give the full code? I need instances of operations for Vec3<T>, otherwise I can't compile this particular snippet.
This probably happens because Vec3<T> doesn't implement Float. However, given the current situation you probably won't be able to use One separately from Float, and you also probably won't be able to implement Float for Vec3<T>... I guess you will have to implement your own method to create Vec3<T> basic constants.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.