为什么Rust的运算符具有Output变量类型?

Mut*_*pus 9 generics operator-overloading rust

我一直在线阅读Rust书,我已经达到4.1,操作员和重载.我注意到,std::ops::Add将其定义为fn add(self, rhs: RHS) -> Self::Output;具有type Output在该性状分别定义的.

我理解这里发生了什么:add函数接受左侧作为self,右侧接受通用参数类型RHS.

我想知道为什么用Output别名定义输出类型,而不是另一个泛型(例如Add<RHS, Output>)?它只是一个惯例,还是有特定的理由?

pah*_*olg 10

当函数对变量进行操作时,您可以将特征视为对类型进行操作的函数.当想到这种方式时,类型参数用作函数的输入,相关类型用作输出.

由于Output是关联的类型,两种类型的AB我们希望impl Add,我们仅限于采摘单一Output类型.是Output一个类型参数,我们可以impl AddAB在无数种方法.

例如,让我们定义一个Mul特征,其中Output是一个参数:

trait Mul<RHS, Output> {
    fn mul(self, rhs: RHS) -> Output;
}
Run Code Online (Sandbox Code Playgroud)

现在让我们定义一个Complex类型:

#[derive(Debug, Clone, Copy)]
struct Complex {
    x: f64,
    y: f64,
}

impl Complex {
    fn new(x: f64, y: f64) -> Complex {
        Complex { x: x, y: y }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们希望能够乘以f64:

impl Mul<f64, Complex> for Complex {
    fn mul(self, rhs: f64) -> Complex {
        Complex::new(self.x * rhs, self.y * rhs)
    }
}
Run Code Online (Sandbox Code Playgroud)

一切正常.但是,我们可以提出第二个实现:

impl Mul<f64, f64> for Complex {
    fn mul(self, rhs: f64) -> f64 {
        self.x * rhs
    }
}
Run Code Online (Sandbox Code Playgroud)

当我们将a乘以a时Complex,f64应该调用哪个实现是不明确的,并且调用者需要提供额外的类型信息.通过创建Output关联类型,这是不允许的.以下代码会针对冲突实现引发编译器错误:

impl std::ops::Mul<f64> for Complex {
    type Output = Complex;
    fn mul(self, rhs: f64) -> Complex {
        Complex::new(self.x * rhs, self.y * rhs)
    }
}

impl std::ops::Mul<f64> for Complex {
    type Output = f64;
    fn mul(self, rhs: f64) -> Complex {
        self.x * rhs
    }
}
Run Code Online (Sandbox Code Playgroud)

完整的例子


Chr*_*son 5

这是关于谁可以指定输出类型。一般来说,当您将两种类型相乘时,例如f64乘以f64,很清楚结果的类型应该是什么:f64。对于调用者来说,请求结果类型是没有意义的String- 因此它作为输入实际上没有意义。

我可以想象在某些情况下,您可能希望选择不同的输出,但它们有点小众(比如u32*u32返回完整u64结果?);另外,如果有多个选项,您如何指定您想要哪一个?虽然您可以编写Add<u32, u64>::add(a, b),但它会使简单的表达式(如a*b*c歧义)变得模糊,并使类型推断变得更加困难!