- It's very common to pass structure objects
into a function.
This enables you to pass a whole object into a function,
a lot of data all in one go,
much better than passing
a whole load of individual parameters.
You can just pass a single structure,
and all of its data immediately gets passed
into the other function in one fell swoop.
So that's quite handy.
So when you pass values into a function,
you've got two different ways to do it.
You can pass by value, which is what we'll discuss now,
or you can pass by reference,
which we'll discuss a bit later.
So let's imagine we have a function.
This function receives a structure parameter by value.
There's no ampersands, it's not receiving a reference,
it's receiving a structure by value,
and it prints the name and the salary
and the fulltime flag.
Now, the name of the function,
I've called it consume employee,
gives you an indication of what's gonna happen
when we call the function.
So let's see some high level function.
Here we are.
And in here, I declare e1.
So e1 is my employee,
the name, and the salary, and the region.
And then I pass e1 basically up into the function above.
Okay, so e1 gets passed up into here.
So what happens now when you pass by value?
Remember, this is tricky in Rust.
When you pass something by value, what happens?
It depends on whether the type
implements the Copy trait or not.
So what I'm telling you for a fact at the moment,
the structure that we've got,
the employee doesn't implement the Copy trait.
We haven't really seen how to do that yet.
We can and we will, but we haven't done it yet.
So at the moment,
the Employee structure doesn't implement the Copy trait.
So what's gonna happen is it will copy,
it will still copy the data into this employee here, e.
Okay, so the data will be copied into there,
the name, and the salary, and the fulltime status.
A move occurs, basically.
The employee object here used to own the data.
That data is moved into the other structure up here.
The data was moved into this structure object up here.
And this structure basically goes away.
It becomes vacated, a move occurs.
So our function down here loses ownership of the data.
It's gone effectively.
That data has been moved up to here.
So we can use that data in the function.
We can access the name and the salary and so on.
But of course, when this structure goes at the scope,
it will be popped off the stack and it disappears, okay?
So if you do pass a structure
and the structure doesn't implement Copy,
then by passing the structure into a function,
you basically lose that object.
You pass the object into the function,
that receiving function acquires ownership.
And at the end of that function,
the object is dropped, it's destroyed.
It means you can't then use the object anymore down here.
So to summarize the rules,
what happens when you pass a structure into a function?
It depends on whether the structure implements
the Copy trait or not.
If it did, then it would behave more like an integer.
A bitwise copy of the structure
would be passed into the function.
The original function retains ownership
and can use the structure afterwards
as if you were passing integer,
which implement the Copy trait.
If you don't implement the Copy trait for the structure,
and many structures don't implement Copy,
then ownership of the structure is moved
into the called function,
and the caller loses ownership
and can't use the object anymore.
So you have to be careful here.
Right, well, let's have a look at the example.
Same project as before.
The files involved, obviously, mytypes,
which defines the Employee structure.
The main code, which calls my demo function.
And my demo function this time is
in demo_struct_pass_value, pass by value.
Okay, so we'll run the project
once we've had a look at the code.
Let's have a look at the code.
So quick reminder, mytypes,
my Employee structure doesn't implement the Copy trait.
We haven't seen how to do it yet, so it doesn't.
We will see that later.
But at the moment, our structure doesn't implement Copy.
So when we pass by value, a move will occur.
In my main code,
let's uncomment the demo for this part of the example,
demo_struct_pass_value, and it's here.
So I have a function called consume_employee.
It receives an employee and acquires ownership,
accesses the data.
And then at the end of the function,
the employee object will be dropped and it's gone.
It'll be popped off the stack and that's the end of that.
So my calling function creates the original employee, e1,
and it's John again, good old John.
When I pass the object into the function by value,
my code loses ownership.
That employee is now owned by this function,
which uses it and then loses it.
Up here, I can't use the employee again.
I've lost ownership.
The object has moved away into this variable here.
I can't use the original variable up here, okay?
It's defunct.
If I try to, I'm gonna get an error.
It'll say you can't try to borrow this object
because you've moved ownership away into that function.
It's gone now.
So if I ran the code now,
I'd get a compiler error on line 17.
Let's see, cargo check.
Right.
So I've created an employee.
Employee doesn't implement the Copy trait,
meaning when you pass by value,
it will be moved away from you.
You'll lose it.
So it's saying, "What?"
Bear that in mind.
So when you pass e1 into the consume_employee function,
the function did consume it, hence the name.
So the value was moved away from you here into the function.
You don't own it anymore.
So then we need to access the name here on line 17,
you can't try to access the name.
The print function is trying to borrow the employee,
trying to reference it.
It can't because the object has been moved previously.
You can't use the value after it's been moved away.
So, I mean, obviously, one solution would be
to implement the Copy trait on employee.
Another solution would be to pass by reference,
and we'll look at that later.
But if you do pass by value and it doesn't implement Copy,
you will lose the object when you pass the value in, right?
So let me comment out this code for now
and I'll just try running the application as it stands,
just to confirm that it does actually work.
Yes, that compiles.
Let's run it.
Okay, so from the top, I'm in demo_struct_pass_value.
Here I am.
And I create my employee, I pass it,
I move it into that function.
It prints the employee details.
John earns 1K, doesn't say per annum,
maybe that's per minute, and he's not a full-time employee.
The employee object will be dropped here.
So it's gone now,
which means we couldn't access it anymore.
Right, so pass by value for structures
is potentially fraught
because you could and you will lose the object
if the object doesn't implement the Copy trait.
So, maybe you can pass it by reference instead
so that you don't lose ownership.
That's what we're going to look at in the next demo.