[No Audio]
In the previous tutorial, we looked in details
at two specific problems that are dangling
references and the undetermined lifetimes.
In this tutorial, we will be looking at the
concept of lifetime specifiers, which will
enable us to overcome these issues, pretty
much exciting material to cover. So let's get started.
I'm starting with the code that we
have seen in the last tutorial, this program
was having an issue, that was missing lifetime
specifier. Okay, to deal with this problem,
the Rust allows us to specify explicitly
lifetimes which are known as generic lifetime
parameters. A generic lifetime parameter
imposes a lifetime constraint on the
references and the return values of a function.
Let us modify the existing examples
with the help of some generic lifetime parameters.
The generic lifetime parameters
will be specified after the name of the
function, inside less than and greater than symbols.
Typically, small case letters along
with a single quotes are used for this purpose.
Let me add generic lifetime
parameters for the two variables.
[No Audio]
The 'a and 'b are the generic lifetime specifiers,
which will be used by the inputs and outputs of this
function. Next, I would specify to the
compiler that the variable first_str
has a lifetime which is specified by the
'a in the variable second_str
will have a lifetime specifier
which will be specified using the generic
lifetime parameters 'b.
This will have a syntax of &,and after that without any
spaces 'a, and for the second
variable, I will do the same by mentioning
& and immediately followed by 'b.
For the output I will need to mention
which of the two variable's
lifetime the output will be assuming. So I
will mention, let's say 'a, which
tells the compiler that the lifetime of the
returning variable is at least equal to that
of variable first_str. This
program will now compile without any error,
let us execute.
[No Audio]
What will happen if I change the returning
value from a first_str to that of second_str?
In this case, the compiler will complain again.
The error in this case is that of lifetime mismatch. This
is because the returning reference in this
case does not match the returning lifetime,
which is specified as date of 'a.
Now let us look at some important points
with regards to the generic lifetime parameters.
The very first point to note is
that the generic lifetime parameters are only
needed when we use references as outputs from
a function. Let us see this in some detail.
I will write the program that is similar to
program considered in the previous tutorial,
I will declare a couple of variables.
[No Audio]
Next, I will pass these two values by
reference to a function as inputs
[No Audio]
The output will be a simple i32 type integer.
[No Audio]
Inside the function, I will compare the two
numbers, and we'll return the actual value of
the variable which is greater in value.
[No Audio]
In this case, the return is a variable and
not a reference. So therefore, I have added
stars to the values of the variables, because
they are references and we need stars to get
the values from a variable which is a reference.
So in summary, this is the same
program but the return type in this case is
not a reference but rather a value.
Let us call this function from the main.
[No Audio]
You may note that, the compiler is not complaining.
This is because, the issue of lifetime and
undetermined lifetimes is when we use a
reference as a returning value. So the first
point that we should note is that, typically
the generic lifetime parameters are needed
when we use references as function outputs.
The second important point to
note is that, the lifetime parameters are only
specified with references. Let us look into
it with the help of some examples.
I will modify the same program, I will add a
generic to this program.
[No Audio]
Inside a function, I will use
a reference for the variable i and a value
for the variable j.
[No Audio]
For the output, I will add so mentioned the reference.
[No Audio]
I will simplify the body of the program by
just returning the variable i.
In the function call, I will also update the first
parameter to that of reference.
[No Audio]
Now in the Function Parameter List, I will add a generic
lifetime of 'a to that of the variable i,
and also to the output value.
[No Audio]
If I try to add a generic lifetime to that of the
variable j, the compiler will complain.
The point which we wanted to emphasize is that,
the generic lifetime parameters are only
mentioned with the references. If we remove
the lifetime parameters from the variable j
and execute, the program will execute successfully.
[No Audio]
The next point we want to focus is on the
issue with multiple lifetimes. Let us look
again at the program containing the greater
than function. Let us take rid of the
previous code and write fresh.
[No Audio]
I will define a couple of variables.
[No Audio]
Next, I will call the
function greater with two references to the
variable of int1 and int2, and will store
the result in a variable.
[No Audio]
Next, I will define the greater than function
with two references as inputs, and for the
output, I will also mention a reference.
[No Audio]
In the body, I will return the greater of the two values.
[No Audio]
I will now add a couple of generic lifetime parameters.
[No Audio]
I will attach the generic 'a
to the variable i, and in the same way
I will add a generic lifetime parameter b.
[No Audio]
For the output, I will mention lifetime parameter a.
In this case now, there are
different lifetimes for the returning
variable, which can be either i or j. Since
the compiler anticipates that there may be
situation and possibility for the variable j
to be the returning reference, so
therefore, it sees in advance that the
variable j does not match the lifetime of the
returning variable. This means we need to
keep a close eye on the returning values from
a function, which are the places to take care
of with regards to the lifetime.
Let us now look at another important point,
we will modify the same program to illustrate a key
point, that is the lifetime will correspond to
the minimum lifetime in case of association
with multiple variables. I will change the
lifetime parameter for the variable j to that of 'a.
Next in the main function,
I will introduce a code segment, and we'll
introduce the statement of let int2 = 10,
and we'll make a call to the function in
the code segment. I will also add a print
statement to the code segment.
[No Audio]
Now, let us explain this program a bit. The two
references pass to the greater than function
have different lifetimes.
That is, the variable int1 has a different lifetime
than the variable int2, since int2 has a smaller
lifetime, it becomes the concrete lifetime.
This means that all the parameters that have
'a written next to them should
have a lifetime at least as long as int2.
This also means that the variable result which
stores the returned reference should be valid
as long as int2 is valid. Therefore, if we
use the variable result out of the scope of
int2, we get a compilation error. For
instance, if I move the same print statement
to outside the code segment, I will get an error.
[No Audio]
You may note that, it is giving an error
saying that, cannot find result in this scope
Let me redo this.
[No Audio]
The point to note from this
is that, when a lifetime is used in
connection with multiple variables, so we
need to pay special attention to the one that
has the minimum lifetime, as it will become
the concrete lifetime. Now let's look at
another important point, that is
in connection with structures.
Consider the scenario where we have a structure
that has a field which is a reference,
let me define a struct.
[No Audio]
The name field, in this case, is a reference to
a string slice. You may note that, the Rust
compiler is already complaining about the
missing lifetime specifier. The Rust basically
wants that the reference to the field should
live as long enough as the structure itself. Of
course, we do not want to have a structure
with reference field which is pointing to an
invalid resource. To ensure this, we will need
to specify the Rust the lifetime specifier,
so let us add the lifetime
Let us now use the structure. I will first define a variable
called first_name initialized from my name.
[No Audio]
Next I will define an instance of the
structure Person and we'll set its fields.
[No Audio]
I will next include a code segment and
will declare a string variable inside it.
[No Audio]
Finally, I will update the name field to the
reference of the last_name.
[No Audio]
Outside the code segment, I will access the
fields of the structure in a print statement.
[No Audio]
The compiler is giving us an error message,
saying that the variable last_name
did not live long enough. This is because the
requirement due to the lifetime specifier was
that the field should live at least as long
as the structure itself, but it did not live
long enough and it becomes invalid at the end
of the code segment. Please note that, if we
remove the print statement the code will have no issues.
[No Audio]
This is because the structure is
last modified in the same code block in which
the variable last_name is defined.
In other words, both the field and the
structure has the same lifetime. Now, we will
explain a last point which is related to the
issue of using of references to the same variable.
Let us write a simple program to
illustrate this issue. I will declare a
vector, and we'll initialize it from some values.
[No Audio]
I will next create a function which will use
the vector by reference, there will be two
vector references as inputs.
[No Audio]
The output will be a vector reference
[No Audio]
inside the body of the function, I will have a
simple logic for determining the returning value.
[No Audio]
Let us now call this function, I will call it
with the same some_vec as input,
so I will write it twice as inputs.
[No Audio]
This means that, I am passing the same
reference to the function but two types.
As expected without the lifetime parameter, the
Rust will complaint. You may note that,
although we are passing the same vec, Rust
will still complain as it is unable to know
to which variable the output reference may
corresponds to. Although we know that they
are the same, but Rust is unable to detect it,
and therefore it needs explicit information
about lifetimes to avoid possible confusion.
So let us add the lifetime parameters to the
inputs and also with the output.
[No Audio]
Now the program will compile without an issue, let us
cargo run to confirm.
[No Audio]
Okay, that brings us to
the end of this tutorial. We have learned
about the lifetimes and some issues
while using the lifetimes. The special point
to note is that, the lifetime will come into
play, when we have functions that returns
references, or when we have structures with a
reference field. See you again and until next
tutorial happy Rust programming.
[No Audio]