Trying to implement a generic Vec
implementing the std::ops::Add
trait. I want the implementation to automatically convert the underlying type of the vector on addition so I can do something like this:
let u: Vec3<i32> = Vec3 { x: 1, y: 2, z: 3 };
let v: Vec3<i8> = Vec3 { x: 2, y: 3, z: 4 };
let w = u + v;
without using .into()
at call site. I have implemented the From
trait (which automatically add the Into
implementation) and it's working fine on a simple function:
fn foo<T: Into<Vec3<i32>>>(input: T) -> Vec3<i32> {
input.into()
}
let v: Vec3<i8> = Vec3 { x: 2, y: 3, z: 4 };
println!("{:?}", foo(v));
Link to the non-compiling example here. Is it possible to express a constraint on the type of the right hand side argument of an operator and if yes, how?
#![allow(dead_code)]
use std::convert::{From};
use std::ops::{Add};
#[derive(Debug)]
struct Vec3<T> {
x: T,
y: T,
z: T,
}
impl<T: Add<Output=T>> Add<U: Into<Vec3<i32>>> for Vec3<T> {
type Output = Vec3<T>;
fn add(self, rhs: U) -> Self::Output {
let rhs_converted: Vec3<T> = rhs.into();
Vec3 {
x: self.x.add(rhs_converted.x),
y: self.y.add(rhs_converted.y),
z: self.z.add(rhs_converted.z),
}
}
}
impl From<Vec3<i8>> for Vec3<i32> {
fn from(input: Vec3<i8>) -> Self {
Vec3 {
x: input.x.into(),
y: input.y.into(),
z: input.z.into(),
}
}
}
fn foo<T: Into<Vec3<i32>>>(input: T) -> Vec3<i32> {
input.into()
}
fn main() {
let u: Vec3<i32> = Vec3 { x: 1, y: 2, z: 3 };
let v: Vec3<i8> = Vec3 { x: 2, y: 3, z: 4 };
let w = u + v;
// println!("{:?}", foo(v));
println!("{:?}", w);
}
You need to change U: Into<Vec3<i32>>
to U: Into<Vec3<T>>
in your Add
implementation. Also, the type parameter U
declaration was missing from the generic impl
, it should be impl<T, U>
not just impl<T>
. After these minor fixes your code works as expected:
use std::convert::{From};
use std::ops::{Add};
#[derive(Debug)]
struct Vec3<T> {
x: T,
y: T,
z: T,
}
impl From<Vec3<i8>> for Vec3<i32> {
fn from(input: Vec3<i8>) -> Self {
Vec3 {
x: input.x.into(),
y: input.y.into(),
z: input.z.into(),
}
}
}
impl<T, U> Add<U> for Vec3<T>
where T: Add<Output=T>, U: Into<Vec3<T>>
{
type Output = Vec3<T>;
fn add(self, rhs: U) -> Self::Output {
let rhs_converted: Vec3<T> = rhs.into();
Vec3 {
x: self.x.add(rhs_converted.x),
y: self.y.add(rhs_converted.y),
z: self.z.add(rhs_converted.z),
}
}
}
fn main() {
let u: Vec3<i32> = Vec3 { x: 1, y: 2, z: 3 };
let v: Vec3<i8> = Vec3 { x: 2, y: 3, z: 4 };
let w = u + v;
println!("{:?}", w); // prints "Vec3 { x: 3, y: 5, z: 7 }" as expected
}