求教一个关于运算符重载和GC的问题!
如下代码中,我尝试重构Matrix
之间和其与f64
的所有矩阵运算法则。我想求问一下,所有步骤我都返回一个新的Matrix
算是一个比较适合的方法吗?比如let ci = &a + c1 * c2 * &b;
相当于let ci = &Matrix1 + Matrix2
,在我这个代码里,Matrix2
不会被消耗掉,但也不与任何变量绑定,它会在什么时候drop?是赋值给ci
的瞬间,它就被drop了吗?还是在main函数结束时?
第二种办法是只允许&Matrix
参与运算,得到的答案也是&Matrix
。此时,按我的理解是,内存里有一个Matrix
但不与任何变量绑定,而我们手头上只能存在有它的引用&Matrix
。是这样吗?
哪种办法是比较合理,或者说,计算效率最高的呢?我的理解是计算效率是一致的。但是第一种方法,是否会消耗额外的内存。而第二种方法,写起来方便(只用写关于&Matrix
那一套),但手上只有&Matrix
引用会比较不方便吗?
此外,f64 + Matrix
和Matrix + f64
需要写两套,很不方便。比如这里我就忘了写Matrix + &Matrix
。我看ndarray
貌似是用宏解决这个问题,有更简单的方法吗?
fn main() {
let a = Matrix::Array(array![[0.0, 1.0], [2.0, 3.0]]);
let b = Matrix::Array(array![[4.0, 5.0], [6.0, 7.0]]);
let c1 = 0.001f64;
let c2 = 0.5f64;
let ci = &a + c1 * c2 * &b;
}
#[derive(Debug, PartialEq, Clone)]
pub enum Matrix {
Raw(Vec<Vec<f64>>),
RawPureDiagonal(Vec<f64>),
RawSparse(Vec<(usize, usize, f64)>),
Array(Array2<f64>),
PureDiagonal(Array1<f64>),
}
impl<'a, 'b> Add<&'b Matrix> for &'a Matrix {
type Output = Matrix;
// --snip--
}
impl<'a> Add<Matrix> for &'a Matrix {
type Output = Matrix;
fn add(self, other: Matrix) -> Matrix {
match (self, &other) {
// ndarray库运算规则, &Array2 + &Array2 不消耗任何变量,生成一个新的Array2
(Matrix::Array(x), Matrix::Array(y)) => {Matrix::Array(x + y)},
_ => {panic!("Unsupported operations!")},
}
}
}
impl<'a> Mul<f64> for &'a Matrix {
type Output = Matrix;
// --snip--
}
impl Mul<f64> for Matrix {
type Output = Matrix;
// --snip--
}
impl<'a> Mul<&'a Matrix> for f64 {
type Output = Matrix;
fn mul(self, other: &'a Matrix) -> Matrix {
match (self, other) {
// ndarray库运算规则, &Array2 * f64 只消耗f64,生成一个新的Array2
(x, Matrix::Array(y)) => {Matrix::Array(x * y)},
_ => {panic!("Unsupported operations!")},
}
}
}
impl Mul<Matrix> for f64 {
type Output = Matrix;
// --snip--
}
1
共 6 条评论, 1 页
评论区
写评论感谢!不过宏对我来说有点难,我有空尽量看看源代码的宏看看能不能理解完之后抄抄。不过不能只能对于
&Matrix
的重载啊。如a = &[b] + &[c] * &[d]
,假设全部生成Matrix
,显然算到第二步就是a = &[b] + [cd]
,因为&[c] * &[d]
返回了Matrix
。所以我被迫得把所有的都写完。--
👇
Aya0wind: 第二种部分合理,a+b从常理来看就是应该生成一个新的矩阵的。所以其实你只要写一个对于&Matrix的运算符重载就行了,但是Add这个没必要写,你在函数里面没有消耗,就没必要所有权,而且返回的肯定不能是&Matrix而是Matrix。
就写上面这一个就行。
另外运算符两边互换不等价这个是没问题的,用宏其实是普遍做法,你可以看看标准库,这类东西全都用宏做的,直接用一个宏把一堆类型的trait一起实现了,不然工作量很大而且重复代码很多。
感谢!有道理,是我想岔了。显然假如
ADD
函数里生成了一个Matrix
而只传出一个&Matrix
的话,编译器是不会允许通过的,因为这会是一个空指针。同理,第一种方法的直接传入Matrix
和&Matrix
进行处理,不需要考虑drop
的问题。因为传入的Matrix
会在函数完成时自动销毁,而计算出的新Matrix
会被返回。至于自更新这个我得琢磨一下。可以省内存还是不错的,而且自更新按道理比生成新的快一点。
--
👇
Neutron3529: 第二种办法是只允许&Matrix参与运算,得到的答案也是&Matrix。
这是不可能的
你不可能从函数里传出一个引用作为返回值。
最多&Matrix参与运算,返回Matrix
或者&mut Matrix参与运算,返回&mut Matrix(以便接下来的处理)
嗯嗯。不过L+R逻辑与R+L有差异貌似我是用不到了。
--
👇
ezlearning: 关于Drop,可以看看这里哈: https://doc.rust-lang.org/stable/nomicon/drop-flags.html
运算符重载,LHS + RHS 不必须等于 RHS + LHS: https://doc.rust-lang.org/rust-by-example/trait/ops.html
第二种部分合理,a+b从常理来看就是应该生成一个新的矩阵的。所以其实你只要写一个对于&Matrix的运算符重载就行了,但是Add这个没必要写,你在函数里面没有消耗,就没必要所有权,而且返回的肯定不能是&Matrix而是Matrix。
就写上面这一个就行。
另外运算符两边互换不等价这个是没问题的,用宏其实是普遍做法,你可以看看标准库,这类东西全都用宏做的,直接用一个宏把一堆类型的trait一起实现了,不然工作量很大而且重复代码很多。
第二种办法是只允许&Matrix参与运算,得到的答案也是&Matrix。
这是不可能的
你不可能从函数里传出一个引用作为返回值。
最多&Matrix参与运算,返回Matrix
或者&mut Matrix参与运算,返回&mut Matrix(以便接下来的处理)
关于Drop,可以看看这里哈: https://doc.rust-lang.org/stable/nomicon/drop-flags.html
运算符重载,LHS + RHS 不必须等于 RHS + LHS: https://doc.rust-lang.org/rust-by-example/trait/ops.html