[No audio]
Welcome back again in the course.
In this tutorial we will move ahead with the topic
of variables and we'll cover some additional basic topics.
So let's start.
We will first look at how to
initialize multiple variables in a single statement.
To declare more than one variable of the
same or different types, we use a comma
separated list which is enclosed in smooth brackets.
For instance, I will declare two variables with
the name of first_number and second_number,
and we'll set their values accordingly.
[No audio]
The two numbers have different types and
the compiler has successfully inferred their types.
We can always include more variables inside the smooth
brackets if we wish to initialize more variables.
Sometimes we may be dealing with
very large numbers inside our program.
To make the large numbers more readable,
the Rust allows the uses of underscores.
For instance, I will declare a variable large_number
and we'll set its value to that of 1 million.
[No audio]
For better readability of the number, I
can add underscores at the appropriate places.
[No audio]
Sometimes you may mistakenly assign a value to a variable
of a certain type which may exceed the range of
values that particular type of variable may hold.
This is called integer overflow.
For instance, if I declare a variable number of type
u8, to that of a value of 256, you
may note that I got a compile time error.
This is because the upper limit for the u8
is 255, and I am trying to exceed this limit.
Please note that in some older versions of Rust,
the compiler may not complain, but when you execute
it will give you a wrong answer.
Rust also has very easy mechanism to display the decimal
number in other bases such as octal, binary and hexa.
Suppose we have a variable x equals to 255.
I will display the value of this variable
in different formats inside the print statement by
placing special syntax inside the placeholders.
[No audio]
To display the same variable in octal I will
mention colon o inside the placeholder, and for the
hexadecimal I will write colon followed by capital X,
and for the binary colon b.
[No audio]
Let us run to see the output of this program.
[No audio]
Okay, a couple of more points regarding
the variables which are quite handy.
The Rust assume a snake case
convention for the variable names.
The snake case refers to the style of writing variable
names in which first letter of the variables are in
lowercase and each space is replaced with an underscore.
For instance, if I write let Number equals to 45,
you may note that there is an underline beneath the
name of the variable which indicates to me that something
needs our attention and needs to be fixed.
Please note that a red line means an error, while
an underline of this color is not an error.
[No audio]
Let us see the message of compiler
in this case. Alongside other details,
it says the variable name should be snake case.
The program will, however compile
and will not complain.
The Rust, however, will keep on giving us this
message as the Rust wants you to follow the
convention of using snake case for variable names.
If we look at the same message again,
it also warned us about use unused variables.
The compiler basically wants us to use all the
variables that are being declared inside a program.
It makes sense because if we do not use a
variable, then it should not be part of the program.
This is something nice about Rust because it helps
in making sure that we write correct programs.
Whenever you declare some variable and you do not
use it inside the program, then as part of
Rust safety feature, it will keep on reminding you
that you have a variable which is not used.
In the previous tutorial, we pointed out that
you may not be able to perform the
operations on variables of different types.
For instance, an addition operation on
variables of type, integer and float.
We pointed out that there is
a way for making this possible.
To see this, I will declare a couple of variables.
The first variable is n1 with a value of
14, which means that it is an integer variable and
the second variable n2 with a value of 15.6, means that it is a float variable.
I will next try to add these two variables.
[No audio]
As expected, it will give me a compile time error.
One of the reason for this error is that,
as mentioned in the previous tutorial, the Rust is
statically typed language, which means that it must know
the types of all the variables at compile time.
However, in this case it may not be able to infer the
type of n3 because it is confused about its type.
To clear this confusion, we may either
convert the variable n1 to float
or consider changing n2 to integer.
Both the options are available
and we will explore both.
So let me first change the variable n2 to
a type that matches the type of variable n1.
This is done by writing n2 as i32, which
will convert the variable n2 to n i32 variable
during the computation of the value of n3.
Please note that the variable n2 will not be permanently
changed to an i32 type and it will just be
treated as ani32 variable within this command and will
return its type of f64 outside this command.
Let us display the answer of the computation.
[No audio]
You may have noticed something here.
The variable of n2 was having a value of
15.6 and when we changed it to an integer, so
its value has been changed to a value of 15.
Therefore, the final answer is that of 29 instead of
29.6, because the result of two integers will lead to
an integer value and not a float value.
So in this case we have some loss of value.
The takehome message is that we need to
be careful when we are changing the type
of a variable from one type to another.
To get the correct value,
we should better change the value of type
of n1 to that of float instead.
So I will change n1 to f64 instead.
Let us execute again.
[No audio]
This time we have the correct value.
Now we will move to the next topic
of the lecture, which is regarding shadowing.
Shadowing in simple words refers to the concept
of using or updating or declaring a variable
with the same name which has been previously
used or declared in the program.
In the Rust community and literature, we say that the
first variable is being shadowed by the second, which means
that the second variable value is what the program sees
when the variable is used inside the program.
Let us now see the different cases in which
the shadowing of a variable may take place.
The first case is when we shadow a variable by
using the same variable name and using the let keyword.
I will declare a variable s with a value of 5.
In the next line I will declare it again by
assigning it a different value such as 5 times 5.
The Rust will use the most recent or latest value
which shadows the previous value of the variable s.
In this case, the value of the variable
s after executing the program will be 25.
To confirm this, I will add a suitable
print statement and execute to confirm the result.
[No audio]
The second case is when we shadow
a mutable variable by an immutable variable.
For instance, I will declare mutable variable p
and make it equal to a value of 5.
[No audio]
In the next line I will make it immutable and
will assign it a value of 5 times 5.
This means that the mutable variable p
is being shadowed by its immutable version.
And now in the next line, if I try to update its
value by assigning it a value of, let's say 60, so the
compiler will complain and it will give us an error.
The third case of shadowing occurs when
we change the type of a variable.
For instance, I will define a variable q as
an integer by assigning it a value of 32.
In the next line I will change its type to
that of character by assigning it a value of a.
[No audio]
This will shadow its previous type.
We can go ahead and shadow its
type as many times as we like.
The final case of shadowing
occurs inside the code segments.
Code segments are introduced inside
the Rust using curly brackets.
Any code inside the same curly brackets are
said to be defined in the same scope.
To explain how shadowing works inside the code segments,
I will first declare a mutable variable r, and
will initialize it from a value of 65.
[No audio]
Next, I will introduce a code
segment by adding two curly brackets.
Inside these brackets, I will declare a variable r
again and will assign it a value of 60.
I will also display the value of the variable
inside the code segment using a print statement.
[No audio]
Now, outside the code segment, I will
again display the value of the variable.
[No audio]
Now, let us explain what will
be the output of this program.
First, we should note that every variable in Rust
has an associated scope in which it is known
and its value is valid within that scope.
Outside the scope, the variable will not be known.
The variables defined inside a code segment has a
scope that is limited to that particular code segment.
Variables not in any code segment has
scope equal to the main function.
We will explain the concept of scope in
more detail when we cover the lifetimes.
Now, once we understand this, now,
let us look at the code.
First, we define a variable r, which
will have a value of 65.
Inside the code segment, we declare variable r
again with the let keyword having a value
of 60, which shadows its previous value.
Since this variable r is residing inside the code segment,
therefore, its value will only be retained within the boundaries
of this code segment, which is its scope.
In other words, the effect of shadowing
will be limited to this particular code
segment and will not be reflected outside.
When the scope ends, the value of the
variable r would return back to its original
value and the original value which is 65.
The point to note is that when a value
is being shadowed with the let keyword in a
scope, it only remains in that scope and will
return to its value once the scope is over.
Let us execute to confirm the value of
the variable inside and outside the code segments.
[No audio]
If we, however remove the let keyword from
the variable r inside the code segment, then
the value of r will be permanently changed.
Let us change the value and execute again.
[No audio]
We may note that inside and outside the code
segment, the value of the variable is the same.
Let us now move to the final
topic and that is related to constants.
The very first question is, what are constants?
The constants are data values that remains the same and
are not changed every time a program is executed.
Typical examples of constants include mathematical
constants and configuration values that the
program uses. Like variables,
they also have an associated name.
You may be wondering that we
have the immutable variables also, right?
So they have names and do not change.
So what is the essential difference
between an immutable variable and constant?
The first difference is that you are not allowed
to use the keyword of mut with constants.
Constants are always immutable and
cannot be changed to mutable.
Secondly, you will declare constants using the const
keyword instead of the let keyword, and the
type of the value must be annotated.
The compiler will not infer and add the type for you.
It's your responsibility to add the type to it.
Rust's naming convention for constants is to use
all uppercase with underscore between words.
Let us declare a constant called
MAX_SALARY to some value.
[No audio]
As pointed out earlier, the underscore is
used for the sake of readability.
Okay, that brings us to the end of this tutorial.
We have covered some important concepts that are
necessary to give us a quick start.
You may be noticing that we are covering things at
a very slow pace and in quite some detail.
This is because we want to take everyone abroad,
including those who have some Rust knowledge and also
those who are new to Rust programming.
Once we have built sufficient skills and strong
foundations, then we will be covering the material
at a bit faster pace and there will
be more knowledge covered in lesser time.
In the upcoming tutorial we will be
covering more about the compound data types.
Do come back for covering that, and until next tutorial, happy Rust programming.
[No audio]