您可以在没有显式引用或所有权移动的情况下在结构上实现数学操作吗?



我无法弄清楚如何在结构体上拥有干净的数学,而不要求将这些结构值复制到任何地方。

如果你想要一个可以执行数学运算的结构,你可以写这样的东西:

use std::ops::*;
struct Num {
i: i32,
}
impl Add for Num {
type Output = Num;
fn add(self, other: Num) -> Num {
Num {
i: self.i + other.i,
}
}
}

(这是一个简化的示例。一个实际的例子可能是做矢量数学)

这让我们可以编写漂亮的a + (b / (c * d))样式代码。

由于借用语义,上面的代码以a + b + a的速度下降。一旦a被使用,就不能再次使用,因为所有权被转移到了相关功能(即add)。

解决此问题的简单方法是为结构实现Copy

#[derive(Copy)]
struct Num {
i: i32,
}

这意味着当Num传递给add时,它们的值会自动克隆,以便可以干净地删除它们。

但这似乎效率低下!我们不需要到处复制这些结构:它是只读的,我们真的只需要引用它来创建我们要返回的新结构。

这让我认为我们应该在引用上实现数学运算:

impl<'a> Add for &'a Num {
type Output = Num;
fn add(&'a self, other: &'a Num) -> Num {
Num {
i: self.i + other.i,
}
}
}

现在我们有数学运算,我们没有到处克隆数据,但现在我们的数学看起来很恶心!a + (b / (c * d))现在必须&a + &(&b / &(&c * &d)).如果您有值类型引用(例如let a = &Num { /* ... */ }),则无济于事,因为add的返回值仍然是Num

有没有一种干净的方法来实现结构的操作,以便数学运算看起来干净,并且结构值不会到处复制?

相关:

  • 通用数学无需在 rust 中复制

不,特征按价值消耗,没有办法解决这个问题。

但这似乎效率低下!我们不需要到处复制这些结构:它是只读的,我们真的只需要引用它来创建我们要返回的新结构。

我不会担心复制单个整数的效率。这就是计算机所做的。事实上,引用可能会更慢,因为引用基本上也是一个整数,必须复制,然后必须查找一段内存,也将引用的整数复制到寄存器中。

我显然没有复制一个整数!

一个实际的例子可能是做矢量数学

然后问题就变成了让用户感到困惑的问题。如果不查看实现,用户怎么知道a + a是"轻量级"的。如果您(您类型的实现者)知道复制它是轻量级的,则可以将其标记为Copy。如果不是,则需要进行引用。


这就是今天的情况。有一些实验性的工作确实可能会在未来变得更好一点:

想象一下永远不必写 [...] 再次let z = &u * &(&(&u.square() + &(&A * &u)) + &one);

这个实验是从现在延迟的 RFC 生成的。

有趣的是,这种丑陋的语法被称为索伦之眼。

最新更新