gpt4 book ai didi

generics - 使用泛型进行算术运算时不能应用二元运算

转载 作者:行者123 更新时间:2023-11-29 08:04:04 25 4
gpt4 key购买 nike

我正在尝试使用 num crate Float trait 在我的库中实现泛型,但我一直在与编译器作斗争。这有效:

struct Vector<T> {
data: Vec<T>,
}

trait Metric<T> {
fn norm(&self) -> T;
}

impl Metric<f32> for Vector<f32> {
fn norm(&self) -> f32 {
let mut s = 0.0;

for u in &self.data {
s = s + u * u;
}

s.sqrt()
}
}

但这不是:

use num::Float; // 0.2.0

struct Vector<T> {
data: Vec<T>,
}

trait Metric<T> {
fn norm(&self) -> T;
}

impl<T: Float> Metric<T> for Vector<T> {
fn norm(&self) -> T {
let mut s = T::zero();

for u in &self.data {
s = s + u * u;
}

s.sqrt()
}
}

后者给我以下错误:

error[E0369]: binary operation `*` cannot be applied to type `&T`
--> src/lib.rs:16:23
|
16 | s = s + u * u;
| - ^ - &T
| |
| &T
|
= note: an implementation of `std::ops::Mul` might be missing for `&T`

如果我删除引用并迭代 self.data,我会得到一个

error[E0507]: cannot move out of borrowed content
--> src/lib.rs:15:18
|
15 | for u in self.data {
| ^^^^^^^^^ cannot move out of borrowed content

最佳答案

让我们仔细看看 Float 特征。它被定义为:

pub trait Float: NumCast + Num + Copy + Neg<Output = Self> + PartialOrd<Self> {
// ...
}

深入研究 Num 特征,我们看到:

pub trait Num: Zero + One + NumOps<Self, Self> + PartialEq<Self> {
// ...
}

更深入 NumOps

pub trait NumOps<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>
{
// ...
}

这意味着任何实现 Float 的类型能够与其自己的类型相乘。现在让我们回到您的代码。您正在遍历 Vec<T> ,它为您提供每个项目的引用&T .

你有一个 &T并试图将其乘以另一个 &T .这是一个简化的例子:

fn do_a_thing<T>(a: &T, b: &T)
where
T: Float,
{
let z = a * b;
}

这给出了同样的错误:binary operation `*` cannot be applied to type `&T` .

问题是你知道你可以乘以T另一个T .也就是说,您必须显式取消引用变量。自 Float还需要 Copy ,这将起作用:

let z = (*a) * (*b);

对您的原始代码应用相同的更改会使其正常工作:

for u in &self.data {
s = s + (*u) * (*u);
}

您还可以在模式匹配时取消引用迭代器变量:

for &u in &self.data {
s = s + u * u;
}

或者您可以添加另一个绑定(bind),要求对您的类型的引用可以成倍增加:

impl<T> Metric<T> for Vector<T>
where
T: Float,
for<'a> &'a T: std::ops::Mul<&'a T, Output = T>,
{
fn norm(&self) -> T {
let mut s = T::zero();

for u in &self.data {
s = s + u * u;
}

s.sqrt()
}
}

您还可以为 AddAssign 添加一个界限并在正文中编写更简单的代码:

impl<T> Metric<T> for Vector<T>
where
T: Float + std::ops::AddAssign,
for<'a> &'a T: std::ops::Mul<&'a T, Output = T>,
{
fn norm(&self) -> T {
let mut s = T::zero();

for u in &self.data {
s += u * u;
}

s.sqrt()
}
}

另见:

关于generics - 使用泛型进行算术运算时不能应用二元运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34161245/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com