So far, the functions we've created execute a fixed task without context / inputs. But most often we want our functions to produce different outcomes depending on the context behind the function call.
For example, it would be nice if say_hello() would print a personalized message such as "Hello humans" or "Hello cats" or "Hello dogs", depending on the audience instead of "Hello world" no matter what.
Function parameters:
Function parameters allow functions to accept input(s) and perform a task using the input(s). We use parameters as placeholders for information that will be passed to the function when it is called.
When a function is defined, its parameters are specified between the parentheses that follow the function name.
Here is our function with one string parameter, audience:
fn say_hello(audience: &str) {
println!("Hello {}", audience);
}
Calling with arguments:
Then we can call say_hello() and specify the values in the parentheses that follow the function name. The values that are passed to the function when it is called are called arguments.
// Function declaration:
fn say_hello(audience: &str) {
println!("Hello {}", audience);
}
// Function call:
say_hello("humans"); // Output: Hello humans
We have passed one string argument: "humans". Inside the function audience will equal string "humans" and acts just like a regular variable.
Multiple parameters:
A function can have as many parameters as it needs. Here is a function with two parameters:
fn say_hello(name: &str, age: i32) {
println!("{}, aged {}", name, age);
}
// Let's call it:
say_hello("John", 30); // Output: John, aged 30
say_hello("Mary", 26); // Output: Mary, aged 26
Notice that the order in which arguments are passed and assigned follows the order that the parameters are declared.
Variables as arguments:
Variables can also be passed as arguments for function calls:
fn say_hello(name: &str, age: i32) {
println!("{}, aged {}", name, age);
}
let name = "Andy";
let age = 28;
say_hello(name, age); // Output: Andy, aged 28
say_hello("Mary", age); // Output: Mary, aged 28
Ownership & borrowing:
Passing a value can move it — give away ownership, so you can't use it afterwards. To let a function read a value without taking it, pass a reference with & (a 'borrow'); use &mut to let it modify the value. In short: & lets a function use a value without owning it.
fn greet(name: &str) { // borrows name, does not take it
println!("Hello {}", name);
}
let name = String::from("Andy");
greet(&name); // lend a reference
println!("{}", name); // still usable — we only borrowed it
That's why parameter types in the coding tutorials often show a &, like name: &str.
Assignment
Follow the Coding Tutorial and let's write some functions.
Hint
Look at the examples above if you get stuck.
Free plan: 30 tutor messages. Premium is unlimited.