I'm writing an application in Rust that will have to use vector arithmetic intensively and I stumbled upon a problem of designing operator overload for a structure type.
So I have a vector structure like that:
struct Vector3d {
pub x: f64,
pub y: f64,
pub z: f64,
}
and I want to be able to write something like that:
let x = Vector3d {x: 1.0, y: 0.0, z: 0.0};
let y = Vector3d {x: -1.0, y: 0.0, z: 0.0};
let u = x + y;
As far as I can see, there are three different ways to do it:
Implement std::ops::Add
trait for Vector3d
directly. That works, but this trait's method signature is:
fn add(self, other: Vector3d)
So it will invalidate its arguments after usage (because it moves them) which is undesirable in my case since many vectors will be used in multiple expressions.
Implement Add
trait for Vector3d
and also implement the Copy
trait. This works, but I feel iffy on that since Vector3d
isn't exactly a lightweight thing (24 bytes at least) that can be copied quickly, especially when there are many calls to arithmetic functions.
Implement Add
for references to Vector3d
, as suggested here. This works, but in order to apply the operator, I will have to write
let u = &x + &y;
I don't like this notation because it doesn't exactly looks like its mathematic equivalent, just u = x + y
.
I'm not sure which variant is optimal. So, the question is: is there a way to overload the '+' operator in such a way that
u = x + y
instead of u = &x + &y
? Is there a way to overload the '+' operator in such a way that
- It accepts its arguments as references instead of copying or moving them;
- It allows to write just
u = x + y
instead ofu = &x + &y
?
No, there is no way to do that. Rust greatly values explicitness and hardly converts between types automatically.
However, the solution to your problem is simple: just #[derive(Copy)]
. I can assure you that 24 bytes are not a lot. Computers these days love to crunch a lot of data at once instead of working on little chunks of data.
Apart from that, Copy
is not really about the performance overhead of copying/cloning:
Types that can be copied by simply copying bits (i.e.
memcpy
).
And later in the documentation:
Generally speaking, if your type can implement
Copy
, it should.
Your type Vector3d
can be copied by just copying bits, so it should implement Copy
(by just #[derive()]
ing it).
The performance overhead is a different question. If you have a type that can (and thus does) implement Copy
, but you still think the type is too big (again: 24 bytes aren't!), you should design all your methods in a way that they accept references (it's not that easy; please read Matthieu's comment). This also includes the Add
impl. And if you want to pass something to a function by reference, the programmer shall explicitly write it. That's what Rust's philosophy would say anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With