- [Instructor] In this section,
we're going to see how to return a mutable reference
from a function.
But first, a quick reminder
of how to return an immutable reference from a function.
Here's an example,
similar to what we saw at the end of the previous demo.
I've got a function called get_first_word
and it takes in a string slice
and it returns a string slice.
Let's actually just go through this
to see what it was going to do.
At the top, I have a string,
I'll draw it here.
S is my string and it contains hello world.
Okey-dokey.
And then I pass a reference to string.
Basically I pass a string reference
into this parameter here,
which is of type &str.
And remember, you can always take a string reference
and assign it to a string slice.
That is allowed.
That's one of the built-in rules in Rust.
So we end up with this variable here.
This is a slice that basically points there like that
and it knows that it's like 11 or 12 characters long.
And then if you remember what the function does,
it kind of finds the position of first space
and then it returns a sub-portion of the string.
So it takes the string
and it returns, starting at position zero,
up to but not including the position of the space,
it returns a slice that refers to this portion.
Okay, so if I can draw that like so,
the slice that it returns basically indicates
that's the starting point and five characters in size.
So it kind of indicates
that slice there is what gets returned.
Okay, that's the return slice here.
And we assign that to r1.
So when we print r1,
it prints, well basically it prints hello.
Right, so that actually was quite a nice example
of how you'd pass references into and out of a function.
But of course in this example,
all the references here are immutable.
So what we're gonna look at now
is how to deal with mutable references.
And to be honest, it's mostly the same.
It's just that you put the mut keyword here and there.
So this is how you specify
that a function returns a mutable reference type.
You say it's a mutable reference to some type.
It means that what you pass back to the caller,
the caller is then allowed to change,
you know, the value you've returned.
So that's how you specify
that you return a mutable reference.
To actually do it,
then you specify an &mut well.
You take some value of the designated type
and you return a mutable reference to it
back to the caller.
So the caller can then change the value
that you're referring to.
So, dos and don'ts, things to remember,
do comply with the borrow checker.
Remember the borrow checker in Rust.
The compiler's very fussy.
You can only have one mutable reference
to an object at a time.
Okay, and the rules still apply here.
You can only have one mutable reference at a time.
Also, don't return a dangling reference.
Don't try to return a reference to a local object.
The compiler will complain.
It'll say this object is gonna go out of scope
at the end of the function.
You can't return a reference
because it's gonna disappear in half a second.
So don't return references
to local stack-based objects.
Right, and now imagine that you call the function
which does return a mutable reference
and you want to assign that
to a variable in your call in function.
Simple enough
using implicit type in,
if you call a function
that returns a mutable reference.
Implicitly, that variable would be a mutable reference.
You can use explicit typing, if you prefer.
You can say r is a mutable reference
to whatever type it returns.
So again, we have the choice.
You can either use implicit typing
based on the return type of the function,
or you can use explicit typing
if you feel that that makes your code more readable.
Up to you, really.
Personally, I prefer implicit typing
because there's less noise.
It makes the code easier to read and understand.
Right, well that was actually quite straightforward.
We'll have a look at an example and then we'll run it.
So here's the example.
In my main code,
I'll comment out the example that we had before
and I'll uncomment the example that we need now.
demo_returning_mutable_reference.
And it's here.
So I have a function,
it takes a mutable reference to a string,
and here is,
well obviously the original object also has to be mutable
otherwise you can't take a mutable reference
to it in the first place.
I've got a mutable string, hello,
I take a mutable reference,
or as the Rustation would say,
I borrow it mutably.
I pass a mutable reference into here.
So that's basically,
this is a reference to that string.
I append,
so it's gonna be hello world.
And I return s.
Well, s is a mutable reference.
So when you return s, remember,
when you have an expression,
it's as if you returned it as a statement
but across the Rustation we'd write it that way.
So, return s as a mutable reference.
So this is a mutable reference
and that's what we said we'd return.
So r is a mutable reference
to the same string as we've been dealing with.
R is basically a mutable reference to this
which means we can add something else.
We can add something else.
So it was, hello,
we appended world,
and now we're appending,
and goodbye.
hello world and goodbye.
And then finally we print out the reference string
like so.
I feel good about this example.
I think it's gonna work.
Okay, so hello world and goodbye.
There we are.
So that is the end of the lesson.
We've talked about how to pass parameters into a function
by value, by reference, or by mutable reference.
The main thing to be careful there
when you're passing by value
is whether you are moving ownership of the object
into the function and losing it from your call in function.
So you might prefer to pass by reference
which borrows the value but doesn't own it
and mutable reference if you need to change the value.
And then of course you can return for a function
you can return a value,
transfer ownership back to the caller,
or you can return a reference or a mutable reference.
And then you have to be careful
that the thing you're referring to
has a long enough lifetime so it doesn't disappear
before the calling function can actually use the reference.