6

我不知道如何在不要求将这些结构值复制到任何地方的情况下对结构进行干净的数学运算。

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

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,
}

这意味着当Nums 传递给时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仍然是 a Num

有没有一种干净的方法来实现结构的操作,使得数学运算看起来很干净,并且结构值不会被复制到任何地方?

有关的:

4

1 回答 1

4

不; 特征按价值消耗,这是没有办法的。

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

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

我很明显[ly]没有复制一个整数!

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

那么问题就变成了让您的用户感到困惑的问题之一。如果不查看实现,用户怎么会知道它a + a是否“轻量级”。如果您,您的类型的实现者,知道复制它是轻量级的,则标记它Copy。如果不是,则需要进行参考。


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

let z = &u * &(&(&u.square() + &(&A * &u)) + &one);想象一下再也不用写 [...]

这个实验源于现在推迟的 RFC

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

于 2018-03-01T22:59:00.063 回答