【问题标题】:How to constrain type of right hand side parameter of operator implementation?如何约束运算符实现的右侧参数类型?
【发布时间】:2020-06-27 16:24:01
【问题描述】:

尝试实现一个通用的 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));

链接到非编译示例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);
}

【问题讨论】:

  • 请注意,自动类型转换不被视为惯用的 Rust,并且在语言及其标准库中有意避免。

标签: generics rust polymorphism traits parametric-polymorphism


【解决方案1】:

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

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

【讨论】:

  • 这允许u + v,但不允许v + u,这个实现不容易添加。
  • @mcarton 可以通过不同的实现轻松添加吗?
猜你喜欢
  • 2017-11-28
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多