你能在没有显式引用或所有权移动的情况下对结构实现数学操作吗?
Can you implement math ops on structs without explicit references or ownership moving?
我不知道如何在不要求将这些结构值复制到任何地方的情况下对结构进行清晰的数学计算。
如果你想要一个可以对其进行数学运算的结构,你可以这样写:
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
时,它们的值会自动克隆,以便可以干净地删除它们。
但这似乎效率不高!我们不需要在所有地方复制这些结构:它是只读的,我们真的只需要引用它来创建我们正在 returning 的新结构。
这让我认为我们应该在引用上实现数学运算:
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
的 return 值仍然是 Num
.
是否有一种干净的方法来实现结构的操作,使数学运算看起来干净,并且结构值不会被复制到任何地方?
相关:
- Generic math without copying in rust
没有;特征按价值消耗,没有办法解决这个问题。
But this seems inefficient! We don't need these structs to be duplicated all over the place: it's read-only, and we really just need it to be referenced to create the new structure we're returning.
我不会担心复制单个整数的效率。这就是计算机 所做的 。事实上,引用可能会更慢,因为引用基本上也是一个必须复制的整数,然后必须查找一块内存,also 复制 referred-to 整数存入寄存器。
I'm obvious[ly] not copying a single integer!
An actual example might be doing Vector maths
那么问题就变成了让您的用户感到困惑的问题之一。如果不查看实现,用户如何知道 a + a
是否为 "lightweight"。如果你,你的类型的实现者,知道它是轻量级的复制,你将它标记为 Copy
。如果不是,则需要进行参考。
今天就是这种情况。有一些 experimental work 可能确实会让这个在未来变得更好一点:
imagine never having to write [...] let z = &u * &(&(&u.square() + &(&A * &u)) + &one);
again
此实验源自 a now-deferred RFC。
顺便说一句,这种丑陋的语法被称为 Eye of Sauron。
我不知道如何在不要求将这些结构值复制到任何地方的情况下对结构进行清晰的数学计算。
如果你想要一个可以对其进行数学运算的结构,你可以这样写:
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
时,它们的值会自动克隆,以便可以干净地删除它们。
但这似乎效率不高!我们不需要在所有地方复制这些结构:它是只读的,我们真的只需要引用它来创建我们正在 returning 的新结构。
这让我认为我们应该在引用上实现数学运算:
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
的 return 值仍然是 Num
.
是否有一种干净的方法来实现结构的操作,使数学运算看起来干净,并且结构值不会被复制到任何地方?
相关:
- Generic math without copying in rust
没有;特征按价值消耗,没有办法解决这个问题。
But this seems inefficient! We don't need these structs to be duplicated all over the place: it's read-only, and we really just need it to be referenced to create the new structure we're returning.
我不会担心复制单个整数的效率。这就是计算机 所做的 。事实上,引用可能会更慢,因为引用基本上也是一个必须复制的整数,然后必须查找一块内存,also 复制 referred-to 整数存入寄存器。
I'm obvious[ly] not copying a single integer!
An actual example might be doing Vector maths
那么问题就变成了让您的用户感到困惑的问题之一。如果不查看实现,用户如何知道 a + a
是否为 "lightweight"。如果你,你的类型的实现者,知道它是轻量级的复制,你将它标记为 Copy
。如果不是,则需要进行参考。
今天就是这种情况。有一些 experimental work 可能确实会让这个在未来变得更好一点:
imagine never having to write [...]
let z = &u * &(&(&u.square() + &(&A * &u)) + &one);
again
此实验源自 a now-deferred RFC。
顺便说一句,这种丑陋的语法被称为 Eye of Sauron。