SCd*_*CdF 6 rust borrow-checker borrowing
我无法弄清楚如何在结构上拥有干净的数学,而不需要在任何地方复制这些结构值.
如果你想要一个可以执行数学运算的结构,你可以这样写:
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,
}
}
}
Run Code Online (Sandbox Code Playgroud)
(这是一个简化的例子.一个实际的例子可能是做矢量数学)
这让我们可以编写漂亮的a + (b / (c * d))样式代码.
由于借用语义,上面的代码很快就会崩溃a + b + a.一旦a使用它就不能再次使用,因为所有权被转移到相关功能(即add).
解决这个问题的简单方法是Copy为结构实现:
#[derive(Copy)]
struct Num {
i: i32,
}
Run Code Online (Sandbox Code Playgroud)
这意味着当Num传递s 时add,它们的值会自动克隆,以便可以干净地删除它们.
但这似乎效率低下!我们不需要在整个地方复制这些结构:它是只读的,我们真的只需要引用它来创建我们返回的新结构.
这让我认为我们应该在引用上实现数学运算:
impl<'a> Add for &'a Num {
type Output = Num;
fn add(&'a self, other: &'a Num) -> Num {
Num {
i: self.i + other.i,
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们有数学运算,我们不是在那里克隆数据,但现在我们的数学看起来很糟糕!a + (b / (c * d))现在一定是&a + &(&b / &(&c * &d)).如果你有值类型引用(例如let a = &Num { /* ... */ }),它没有帮助,因为返回值add仍然是a Num.
是否有一种干净的方法来实现结构的操作,使数学运算看起来干净,并且结构值不会被复制到任何地方?
有关:
不; 特征按价值消耗,没有办法解决这个问题。
但这似乎效率很低!我们不需要到处复制这些结构:它是只读的,我们实际上只需要引用它来创建我们返回的新结构。
我不会担心复制单个整数的效率。这就是计算机的作用。事实上,引用可能会更慢,因为引用基本上也是一个必须复制的整数,然后必须查找一块内存,还将引用的整数复制到寄存器中。
很明显我没有复制单个整数!
一个实际的例子可能是做向量数学
那么问题就变成了让用户感到困惑。如果不查看实现,用户怎么知道它a + a是否是“轻量级”的。如果你,你的类型的实现者,知道它是轻量级的,可以复制,你就标记它Copy。如果不是,则需要进行参考。
这就是今天的情况。有一些实验性的工作可能确实会让这在未来变得更好一些:
let z = &u * &(&(&u.square() + &(&A * &u)) + &one);想象一下再也不用写[...]
该实验源于现已推迟的 RFC。
有趣的是,这种丑陋的语法被称为索伦之眼。