References and Copy Trait in Rust.
Here, we will cover a very simple and basic topic in Rust. The relation between reference (&
) and Copy
trait.
What happens above is that struct Cat
is passed to thetest
function. This compiles fine. Now let’s what happens if I add one more call to the functiontest
:
error[E0382]: use of moved value: `c`
--> src/main.rs:11:10
|
10 | test (c);
| - value moved here
11 | test (c);
| ^ value used here after move
|
= note: move occurs because `c` has type `Cat`, which does not implement the `Copy` trait
The error is pretty simple, telling you that you cannot use a moved variable, since Cat
does not have the Copy
trait, as evident from the Cat
’s definition. The value got moved in the first call to the function test
. Note that instead of using a function, the same can also be demonstrated like this:
let c = Cat{ name: String::from("meow") };
let d = c;
let e = c;
This code will complain about the same thing at assignment to e
for using a moved variable c
. c
got moved into d
before assigning
it to e
.
Ok! back to using function. Now, let’s make T
a Copy
type. But why? Because Cat
got moved
. Ok… so? So it means it can’t be copied and to quickly prove that, let’s make T
as a receiver for theCopy
type.
fn test <T> (t:T) where T:Copy {
}
… and the code fails to compile with the following error.
error[E0277]: the trait bound `Cat: std::marker::Copy` is not satisfied
--> src/main.rs:10:4
|
10 | test (c);
| ^^^^ the trait `std::marker::Copy` is not implemented for `Cat`
|
note: required by `test`
--> src/main.rs:5:1
|
5 | fn test <T> (t:T) where T:Copy {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
But this time, right at the first call to the functiontest
! The previous one had detected the issue at the second call. Unlike the previous one, over here there is an argument mismatch as Cat
does not have theCopy
trait whereas the function test
, now only accepts the Copy
types.
Now, lets switch back to the older definition of function test
and instead pass a &
type to test
.
The compilation succeeds. Also, multiple calls to the function test
do not irk the compiler. We can demonstrate the same concept like this:
let c = Cat{ name: String::from("meow") };
let d = &c;
let e = d;
let f = &c;
This was pretty straight forward and it’s obvious that this _has_to_ work because there are references being passed around and not values. Basically, there are multiple immutable
references being taken. Pretty simple!
All done, now we can take a step back and realise that the reason it works is because the &
type in Rust derives the Copy
trait . Let’s again make T
a Copy
type.
fn test <T> (t:T) where T:Copy {
}
… and the code compiles this time. So in a nutshell, the &
type is just like any other primitive type for eg. integer i32
in this regard. It silently derives the Copy
trait. This is built-in and is a part of prelude. Prelude is “the list of things that Rust automatically imports into every Rust program”.
So how do we pass copies of Cat
around, so that the original variable can be used further? or is it even allowed for Cat
over here to be a Copy
type in first place? For that we will have to look into things like derive
mechanism in Rust and Copy
's sibling called Clone
. Topic for another discussion!