Function Parameters and Arguments

Function parameters vs. arguments

In Rust, function parameters and arguments are used to create functions that can work with external data.

Parameters and arguments are easily confused and often referred to incorrectly. But they are easy to understand:

  • Parameters live in the function definition.
  • Arguments live in the function call.

What Are Function Parameters?

Function parameters are temporary variables that are declared in the function definition and can be used in the body of the function. Their scope is limited to the function code block.

Function parameters must be placed inside the parentheses following the function name. They must include the data type as well:

fn my_function(param1: type1, param2: type2) {}

Consider the parameters num1 and num2 in the following example:

fn subtract(num1: i32,num2: i32) {
    println!("The difference is: {}", num1 - num2);
} 

subtract(2,3);

Standard Output:

The difference is: -1

This function takes two numbers and subtracts the second from the first. This is done using parameters to assign the value of each number to a corresponding variable, num1 and num2.

Rust requires all parameters to be used, which improves code safety and performance by minimizing unused variables.

The final line of code in the example above shows the subtract() function call, including arguments that are sent to the function to be assigned to each parameter.

What Are Function Arguments?

Function arguments are values passed to the function when it is called.

Arguments are essentially the ‘call side’ of function parameters. A function call must include the same number of arguments as there are parameters, and the type of each argument must match the type of the parameter.

Consider the following example:

fn average(num1: i32,num2: i32) {
    println!("The average is: {}", (num1 + num2) / 2);
} 

    average(2,6);

Standard Output:

The average is: 4

The average() function calculates the mean of two numbers. To do so, it uses two parameters: num1 and num2. When we call the average() function, we must use two arguments that match the types of num1 and num2. In this case, both parameters are 32 bit integers and the arguments are ‘2’ and ‘6’.

These arguments are passed to the average() function, where they are assigned to num1 and num2.

If we accidentally used the wrong number of arguments or the wrong type of arguments (e.g. a string or a Boolean), then this function wouldn’t compile properly.

Passing Arguments Using a Variable

Instead of directly passing a value, we can pass an argument to a function using a variable. This allows us to work with variables rather than values, which makes the code more organized and easier to work with.

Consider the following:

    fn sum(num1:i32,num2:i32) {
        println!("Sum : {}", num1+num2);
    }

    let num1 = 2;
    let num2 = 3;
    sum(num1,num2);

Instead of directly passing the values of num1 and num2 to the sum() function, we instead created new variables that can store any number.

Steps like this are critical to improving code readability. Variables are typically named based on their function, making it easy to parse the code and make changes if needed.

Passing Arguments by Reference

Thus far we have seen arguments that have been passed by value. In this case, the value is passed into the function and any changes that occur to the value of the parameter have no influence outside of the function body.

There are cases when it is useful to be able to pass an argument to a function and have it make changes that can be seen outside the function itself. In order to do so, we need to pass the arguments to the function by reference.

References are denoted in Rust using an ampersand ‘&‘.

In the example below, we are using the increment() function to increase the value of a number by 1. We want the number to be permanently changed after the function call, so we pass the argument by reference.

fn increment(num:&mut i32) {
    *num += 1;
    println!("Incrementing to : {}", num);
} 

let mut num = 3;
println!("Initial value : {}", num);
increment(&mut num);
println!("Value after function call : {}", num);

Standard Output:

Initial value : 3
Incrementing to : 4
Value after function call : 4

The num variable retained the incremented value after the function call.