如何约束运算符实现的右侧参数类型?

How to constrain type of right hand side parameter of operator implementation?

正在尝试实现通用 Vec 以实现 std::ops::Add 特性。我希望实现在加法时自动转换向量的基础类型,这样我就可以做这样的事情:

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;

在呼叫站点不使用 .into()。我已经实现了 From 特性(它会自动添加 Into 实现)并且它在一个简单的函数上运行良好:

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 到 非编译 示例 here。是否可以表达对运算符右侧参数类型的约束,如果可以,如何表达?

#![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);
}

您需要在 Add 实施中将 U: Into<Vec3<i32>> 更改为 U: Into<Vec3<T>>。此外,泛型 impl 中缺少类型参数 U 声明,它应该是 impl<T, U> 而不仅仅是 impl<T>。在这些小修复之后,您的代码将按预期工作:

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
}

playground