As part of a "learn Rust" project, I've been working through some Project Euler problems, in which it would be convenient to have a few generic math functions. As an example, let's say I want to write a generic "square" function. If I can live with the builtin numeric types (all of which I believe are Copy), I can write this:
fn square<A>(n: A) -> A
where
A: Mul<Output = A> + Copy,
{
n.mul(n)
}
This seems to work fine. But what if I want to use a numeric type that is not Copy? Say I'm using a bignum library in which numbers are not Copy, but which implements std::ops::Mul. I would have thought I could do this:
fn square_ref<'a, A>(n: &'a A) -> A
where
A: Mul<&'a A, Output = A>,
{
n.mul(n)
}
but that gets me the following error:
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> src/main.rs:16:5
|
16 | n.mul(n)
| ^ move occurs because `*n` has type `A`, which does not implement the `Copy` trait
error: aborting due to previous error
Why does the call to mul
insist on resolving to type A, instead of &A? Just to be clear, my question isn't really about generic math in Rust -- I'm hoping that figuring out how to do this sort of thing, or learning why it can't be done, will help me better understand the language in general.
Clone
instead ofCopy
: play.rust-lang.org/… Primitive types will implementClone
the same as they doCopy
, and bignums will haveClone
. Also note that you don't need to writen.mul(n)
insquare
and insquare_ref
, you can writen * n
because*
invokes theMul
trait. – user4815162342clone()
is quite appropriate, e.g. when implementingMul
in terms ofMulAssign
. It's important to be aware of the option to requestClone
, which is the closest equivalent ofCopy
one has for all kinds of numbers (and which will be as performant asCopy
on primitive nums). – user4815162342*=
) and a preserving one (*
). One way to avoid duplication is to implement the more basic one,*=
, and trivially provide*
aslet new = self.clone(); new *= other; new
. In that caseclone()
is not something to avoid, but actually expresses the intent of the code. – user4815162342