[No Audio]
This tutorial is about functions, which is one
of the fundamental and basic concepts in
programming. In addition to functions, we will
also be covering the basics of how to take
user input in Rust, so let's start.
We will start by looking at the details of functions.
A function in a programming language is a
program fragment or segment that is designed
to perform a defined or specific task. For
example, a function may be written that finds
the average of the three supplied numbers.
Once written, this function may be used many
times without having to rewrite it over and
over again. Functions are a great way for
organizing your code, and give a modular
structure and look to your code, and are
frequently being used almost across all
programming languages. Two basic
terminologies with regards to functions are
known as function call and function
definition. Using the function inside the
main program to perform certain task is
called a function call, and defining the
function or the code segment inside a
function is called function definition.
Please note that the functions are written
outside the main function. The main function
as the name suggests, is also a function
which is like an entry point into the code,
this function will always get a chance to execute.
A function will take zero or many
inputs and will have zero or many outputs,
let us define a very basic function with no
inputs and outputs. As pointed out, the
functions are written outside the main
function. So I will go outside the body of
the main function. This curly braket marks
the end of the main function. After this
curly brackets, I will define a simple
function, functions are declared using the
reserved word of fn followed by the name of
the function. I will define a function with
the name of basic_fn, after the
name of the function, we need to put smooth
brackets, if there are any inputs to the
function, they will be provided inside these
brackets. Next, we will need to put two curly
brackets which indicates the starting and
ending part of the function. All the code
that is between these two curly brackets are
called the function body. Let us assume that
this function is going to print some message
to the user. Let me add a simple print
statement for this purpose.
[No Audio]
Let us execute now.
[No Audio]
You may note that we do not have any output
this is because by default, the compiler will
only run the main function, since the
function basic_fn is outside the
body of the main function, therefore, it is
not going to be executed. To make sure that
it is being executed we will need to call
this function in the main function by writing
the name of this function.
[No Audio]
If I cargo run this now, you may note that
the function executed in this case now, and we
are therefore having the corresponding print
message appearing on the terminal. This means
that the function will only get a chance to
execute when we make a call to the function.
We may call the function many times, and each
time we call it, we will have this output on
the terminal. We do not need to rewrite the
whole code over and over again. We will just
refer to the code inside the function by
calling it as many times as we like.
Let us now learn functions having some inputs.
Outside the main function, I will define
another function with the name of, function_with_inputs.
[No Audio]
Inside these smooth brackets, I will declare some
variables, that I want this function to accept
as inputs and the first one will be a string
reference variable. I will first write its
name, and then I will mention its type.
[No Audio]
I will add one more input variable the name of the
variable will be salary, and the type will be an i32.
I want this function to
display the two inputs, so I will write a
print statement.
[No Audio]
Let us call this function from the main now
with the inputs of Nouman and 40,000.
[No Audio]
In this case now, the first argument is the
string and the second argument is an i32.
If we provide different inputs to the
function, the Rust compiler will complain.
Because the function input needs to be
in the same order and of the same type, as
defined in the function definition.
Let us execute this.
[No Audio]
We can confirm that the two
inputs are being displayed. We can also call
the same function by providing inputs in the
form of variables instead of some fixed
values, let us declare a couple of variables
of type string and integer, the string
variable will contain the string of Kamran
and the integer variable will have a value of 50,000.
I will call the function now with
these two variables as inputs.
[No Audio]
Let us execute now.
[No Audio]
Yes as expected the two variables are
being passed to the function and appropriate
printing function has been successfully executed.
Functions can have inputs as well
as outputs, let us learn functions with
outputs. I will write a simple function which
will compute the multiplication result of the
two input numbers and will return the result
of the multiplication. I will name this
function as function_with_inputs_outputs.
There will be two inputs
called num1 and num2 with type of i32.
[No Audio]
The outputs from the
function are specified by a dash followed by
a greater than sign and then the type of the
output, which in this case is i32. Inside the
curly brackets, I will write num1 times num2,
which will compute the multiplication of the two numbers.
the output value from the function is specified by some
expression they do not have any semicolon
afterwards, when the Rust sees such a
statement inside the body of the function, it
assumes that it is the respective output from
the function, when there is one output from
the function then there should be exactly one
such statement where there is no semicolon after it.
If we add another statement after
the multiplication such as num1 + num2,
then in this case, the Rust compiler
will complain and it will rightfully complain
because, there will be a confusion regarding
which value should be the actual output
from the function. Let us remove the
statement of num1 + num2 for now.
Also note that the output value from the
function is also sometimes referred to as
returned value. The last point in this regards
is that when the function expects a return
value, and the Rust compiler did not found any
expression after which there is no semicolon,
then it will also complain. For instance, if
I add semicolon after the
multiplication operation then there will be
errors in the code saying remove semicolon.
Let's move to the main function, now. I will
run this function by adding a couple of lines
of code in the main function. I will call
this function with the inputs of 10 and 50.
And we'll store the result value in the
variable of answer.
[No Audio]
Let us add a simple print statement
for printing the answer and execute.
[No Audio]
Let us now cover functions with multiple
outputs. The syntax will be very similar
to the function with outputs. To save some
time, I will copy the function that we just
wrote and we'll paste it.
[No Audio]
I will change its name to function with
inputs and multiple outputs.
[No Audio]
To mention multiple outputs from the function
we are required to use the tuples, which are
specified using the smoooth brackets.
Inside the brackets we may mention as many
outputs as we like. Let us mention three outputs
for now all having the same type of i32.
The outputs are not necessarily of the same
type, you are free to change their types. Now
inside the body of the function, I will need
to return a tuple with three values of type i32.
I want the first value in the
tuple to be the result of
multiplication of two numbers, the second
value to be the addition of the two values
and the last value to be the subtraction of
the first number from the second number. Let
us mention these return values as a tuple.
After the tuple I will skip adding the
semicolon which will let the compiler know
that this tuple is going to be the output or
return value from the function. This way we
are able to return multiple values which are
basically residing inside the tuple. To use
this function inside the code, I can either
declare a tuple and receive all the values
inside it or alternatively I can destructure
its value and capture them inside individual
variables. Let us learn both methods.
First, let us destructure the values into the
variables of multiplication addition and
subtraction, I will call the function with
the inputs of 10 and 15.
[No Audio]
Let us print the values now and execute.
[No Audio]
The function is working correctly and
producing the right results. Let us look at
the second method now, I will use a single
tuple to receive all the outputs from the
function, I will store it in a variable of result.
[No Audio]
To access the individual values inside the
result tuple, we will use the .index notation.
So, let us display the individual
values and execute.
[No Audio]
Okay that was it with regards to functions
for now, we will now cover the topic of code
blocks, which is somewhat related to
functions. A code block is some code which is
enclosed inside curly brackets and do some
computations with possible output result.
They are like functions in the
sense that they have a body
and does some specific computation. However,
they do not have an explicit name and we may
not be always able to use them over and over
again, since they have some relevance to
function. So, therefore, we cover them here.
A code block is defined by having some code
inside curly brackets, let us define a
couple of string variables inside the
body of the code block.
[No Audio]
Next, I will use a format macro to make
another string from the two strings.
[No Audio]
I intentionally do not add a semicolon after
the last statement inside the code block and
the reason will become clear to us in a minute.
I want the result from this code
block to be stored in a variable. So at the
start of the code block, I will declare a
variable with the name of full_name
and we'll assign the whole code block to it.
This means that the return value
from the code block will be
assigned to the variable full name. The
return value from the code block is basically
the statement that do not have a semicolon
after it. In this case, it is the format
macro. Let us display the full name after the
code block and execute.
[No Audio]
Okay, great small chunks of code blocks can
be quite handy in arranging your code and
initializing variable and isolating small
computations from the Rust of the code.
This will bring more clarity to the code. Let us
now move to the last topic in today's
learning agenda, which is to learn how to
take inputs in Rust.
Receiving inputs from
the user is important for user interaction
perspective, because sooner or later, you
should be expecting that the program you
write will have an interaction with the user.
Same as in other programming languages. The
earliest use the standard input output
library, to get input from the user. The read_line
function defined in the
standard library is used to read the user
input, in the form of string which we may then
convert into any other format as per our
requirements. Since the read_line reads the
user input into the form of a string, so we
will first create an empty string which will
store the value of the user input, and we will
pass it to the read_line function.
[No Audio]
Next I will use the read_line
function which is part of the standard
library and to access it, we will use the
syntax of std::io::stdin
followed by smooth brackets.
[No Audio]
And then I will mention the read_line function
with the input of the string that we
just created. This function requires a
mutable reference to the string. We will
cover mutable references in the next section.
But for now, just note that it is a reference
to the actual data. But with this type of
reference, you can change the actual contents
residing inside the data. This means that the
input string we pass to it will be changed to
using this function to the value of the user input.
Next in case of any reading error,
which generally is very rare, and would come
from the underlying operating system. Then in
that case, there will be an error, which we
want to handle by using another function
called expected. We will call this function
with with a suitable input message. In case
of error the input message that we pass to
this function will be displayed on the
terminal. If we remove this function the code
will still execute but the Rust compiler will
give us a warning. Please note that the return
value from the function read_line
is of result enum type more details of enums
will be covered later on, but for now, it is
sufficient to know that the result will have
two possible values that is error or &ok.
An okay variant indicate that the
operation was successful and inside okay, we
have the successfully generated value.
The error variant means that the operation failed
and the error contains information about
how or why the operation failed. Now, once we
have the user input, we will next convert it
to a suitable type such as an integer float
char or other to convert to different types,
we will mention the type in which we want to
see the user input. I will consider an f64 format.
So I will write colon followed by f64
after the variable name. Next, I will use
the trim function which will trim the
trailing whitespace is from the string. Next
I will use the parse function on the
resultant trim function. This function parses
the string into another type which in this
case is f64. Finally, we will add an
optional function or expect which will be
executed in case of errors. This will be
executed in case the parse function
is not being able to convert the input string
into the required data type. Let us add a
print statement for displaying the value of
the input and execute.
[No Audio]
The program is asking for the input, I will
provide a value and it prints the same value
back to the screen. Let us cargo run once
more time and this time I will provide a
wrong value. It returns an error message that
is invalid input. If we want to obtain input
in other formats, we may change the type of
f64 to other formats and receive inputs in
different formats. That brings us to the end
of this tutorial and also to the end of this
section. We have focused on covering some
basic programming concepts in this section of
course, in the upcoming section, we will be
covering the Rust central concept of
ownership. I'm quite excited about the next
section, and I believe you will come fresh to
attend that section also for building strong
foundations. With this we end this tutorial
and section see you again and until next
tutorial. Enjoy Rust programming.
[No Audio]