Rust 无法在包含Cow的结构上重载add运算符,因为我无法返回引用本地数据的值

Rust 无法在包含Cow的结构上重载add运算符,因为我无法返回引用本地数据的值,rust,Rust,我正在一个通用字段F上实现矩阵的基本操作。在执行此操作时,我希望为矩阵类型重载add运算符。矩阵类型包含拥有或借用F的Cow。我希望得到的矩阵和借用所添加矩阵的F,而不管它是拥有还是借用F 编译器抱怨我返回了在函数内部创建的引用,但我不明白为什么。在我看来,我引用的是函数的输入参数,而不是本地创建的数据。下面是我的最简单的例子: use std::{ borrow::{Borrow, Cow}, ops::Add, }; pub trait Field { type F

我正在一个通用字段
F
上实现矩阵的基本操作。在执行此操作时,我希望为矩阵类型重载add运算符。矩阵类型包含拥有或借用
F
Cow
。我希望得到的矩阵和借用所添加矩阵的
F
,而不管它是拥有还是借用
F

编译器抱怨我返回了在函数内部创建的引用,但我不明白为什么。在我看来,我引用的是函数的输入参数,而不是本地创建的数据。下面是我的最简单的例子:

use std::{
    borrow::{Borrow, Cow},
    ops::Add,
};

pub trait Field {
    type FElt: Copy + Eq;

    fn zero(&self) -> Self::FElt;
    fn add(&self, a: Self::FElt, b: Self::FElt) -> Self::FElt;
}

pub struct Mat<'a, F: Clone + Eq + Field> {
    field: Cow<'a, F>,
    rows: usize,
    cols: usize,
    data: Vec<F::FElt>,
}

impl<'a, F: Clone + Eq + Field> Mat<'a, F> {
    pub fn zero(field: &'a F, rows: usize, cols: usize) -> Self {
        if rows == 0 || cols == 0 {
            panic!("Empty matrix");
        }

        Self {
            field: Cow::Borrowed(field),
            rows,
            cols,
            data: vec![field.zero(); rows * cols],
        }
    }
}

impl<'a, F: Clone + Eq + Field> Add for Mat<'a, F> {
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        if self.field != other.field {
            panic!("Cannot add matrices: fields do not match");
        }
        if self.rows != other.rows || self.cols != other.cols {
            panic!("Cannot add matrices: dimensions do not match");
        }

        let f: &F = self.field.borrow();
        let mut sum = Mat::zero(f, self.rows, self.cols);
        for i in 0..self.rows * self.cols {
            sum.data[i] = f.add(self.data[i], other.data[i]);
        }
        sum
    }
}

fn main() {}
在我看来,我引用的是函数的输入参数,而不是本地创建的数据

self
可能不是本地创建的,但是它被移动到了
add
方法中(该方法采用
self
),因此当函数返回时它仍然会被销毁。如果允许输出引用它,那么一旦函数返回,引用就会悬空

如果希望输出借用输入,则必须将输入作为参考,这意味着为
和'b Mat
实现
Add
。请参阅注意,
输出
类型必须为
Mat


对于所提出的问题,还有另一个更简单的解决方案。借用不起作用,因为已将
Cow
导入函数。为什么不把它搬出去?一种简单的方法是修改self并返回它,而不是在函数内部创建sum

    fn add(mut self, other: Self) -> Self::Output {
        /* ... */

        for i in 0..self.rows * self.cols {
            self.data[i] = self.field.add(self.data[i], other.data[i]);
        }
        self
    }

你不仅可以避免一个潜在的昂贵的
字段克隆
,而且还可以通过这种方式重用
数据
的缓冲区。

我怀疑你不想要一个
奶牛
,而是想要一个
Rc
(或者更可能是
幻影数据
)。我不知道
Rc
。这正是我想要的,谢谢
PhantomData
不起作用,因为我需要存储有关字段
F
的信息(并且我希望避免在向量
data
的每个元素中重复它)。“借用不起作用,因为Cow被移植到函数中。”=>我知道你在这里做了什么…谢谢你的回答。为参考实现
Add
,但我想为
Mat
&Mat
的所有四种组合实现
Add
,这样我就可以写a+b了。但我想我所有的麻烦都是因为我按照Jmb的建议在应该选择的地方选择了
Cow
。你的简单解决方案在我看来很奇怪。据我所知,如果我写
a+b
,我会得到和,但矩阵
a
也会在这个过程中变异成我不想要的和。@gwafotapa
a
被表达式
a+b
消耗,所以代码无法观察到这一点。例如,这也是
String
实现
Add
的方法。@trentcl我没有想到这一点。我现在明白你的意图了。这是一个很好的解决方案。尽管我现在在代码中使用了
Rc
,但我可以从中获益,这是对我最初问题的一个很好的回答。