trb*_*abb 8 generics operator-overloading traits rust
我有:
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Hilbert:
Add + Sub + Mul + Div + Neg + Mul<f64, Output = Self> + Div<f64, Output = Self> + Sized + Copy
{
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert>(x: T) -> f64 {
let a = (x * 2.0).dot(&x);
let b = (2.0 * x).dot(&x);
a + b
}
Run Code Online (Sandbox Code Playgroud)
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Hilbert:
Add + Sub + Mul + Div + Neg + Mul<f64, Output = Self> + Div<f64, Output = Self> + Sized + Copy
{
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert>(x: T) -> f64 {
let a = (x * 2.0).dot(&x);
let b = (2.0 * x).dot(&x);
a + b
}
Run Code Online (Sandbox Code Playgroud)
我想对所有sH * a平等。在另一个答案的脉络中,我会尝试:a * HHilbertH
impl<T: Hilbert> Mul<T> for f64 {
type Output = T;
fn mul(self, other: T) -> T {
other * self
}
}
Run Code Online (Sandbox Code Playgroud)
但这会产生:
error[E0277]: cannot multiply `T` to `{float}`
--> src/main.rs:12:18
|
12 | let b = (2.0 * x).dot(&x);
| ^ no implementation for `{float} * T`
|
= help: the trait `std::ops::Mul<T>` is not implemented for `{float}`
Run Code Online (Sandbox Code Playgroud)
为什么这是不允许的?为特征对象指定交换乘法的正确方法是什么?
为什么这是不允许的?
Rust 强制执行一个策略,即必须在与 trait 或类型相同的 crate 中定义实现。既不在Mul也不f64在您的板条箱中。
这可以防止关于将使用哪个实现的歧义。这使得编译器很容易强制每个类型最多存在一个特征的实例,因为它只需要检查这些 crate 中的实现。如果任何其他 crate 可以定义实例,那么编译器将不得不到处寻找。但是,试图对代码进行推理的人也必须熟悉每个 crate,以便猜测最终会使用哪种实现。Trait 实现在 Rust 中不是命名项,因此您甚至无法明确说明它。这是一些背景
一种常见的解决方法是使用包装器类型。这样做的运行时成本为零,但它会使 API 变得有点麻烦。
您也可以定义自己的数字特征,刚刚意味着所有的Add,Mul等等,实现的是对所有的基本类型,并用它作为约束Hilbert,而不是所有的个人特质。
但是无论你走哪条路,这都会很混乱。我会质疑对标量、非标量和混合使用相同运算符的好处。这将是迄今为止简单只需添加一个新的方法,以您的API:
fn scale(self, by: f64) -> Self;
Run Code Online (Sandbox Code Playgroud)
除了不会陷入所有这些特征边界和变通方法的复杂混乱之外,代码的意图更加清晰。您无需查看每个变量的类型即可将其与两个标量的乘法区分开来。
fn g<T: Hilbert>(x: T) -> f64 {
let a = x.scale(2.0).dot(&x);
let b = x.scale(2.0).dot(&x);
a + b
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
928 次 |
| 最近记录: |