Start learning free

LESSON 40 OF 414 · FUNCTIONS I

Why Use Parameters and Arguments in Rust

Lesson Read the full explanation

Now that we've learned about function parameters and arguments, let's see why they are so important in our programmers' life:

Consider this: Three students named Andy, Mike and Sally made a mistake. And so their teacher asked each of them to write an apology on the whiteboard.

We can put the apologies in a program like this:

println!("This is Andy");
println!("Andy made a mistake");
println!("Andy suffers the consequences");

println!("This is Mike");
println!("Mike made a mistake");
println!("Mike suffers the consequences");

println!("This is Sally");
println!("Sally made a mistake");
println!("Sally suffers the consequences");

That's decent. But what if we want to change the students' names?

We would have to go through the whole program and change each individual name with the new one.

And if we dealt with 10 students instead of 3 and if the apology text consisted of more than 3 lines, this would quickly get out of hand.


The story with functions:

This is where functions with parameters shine. We can write a function that takes in a student's name as argument and prints the specific apology for that student.

Then, we'll just call the function for each individual student:

fn print_message(name: &str) {
	println!("This is {}", name);
	println!("{} made a mistake", name);
	println!("{} suffers the consequences", name);
}

print_message("Andy");
print_message("Mike");
print_message("Sally");

Changing the story:

Need to change the students' names? We only change the arguments in the function calls.

Need to change the apology text a little bit? We only change it inside the function instead of changing it in the whole program.

fn print_message(name: &str) {
	println!("This is the apology of {}", name);
	println!("{} made a mistake and so {} suffers the consequences", name, name);
}

print_message("Andrei");
print_message("Paul");
print_message("Mary");

Assignment
Follow the Coding Tutorial and let's write some functions.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 5
    Ctrl + Enter to check

    RUST · FUNCTIONS I

    Why Parameters And Arguments in Rust, explained

    The problem with repeated code

    Suppose a teacher asks three students to write an apology, and each apology is three lines long. Written directly, that is nine println! calls, and the only difference between the groups of three is the name:

    println!("This is Andy");
    println!("Andy made a mistake");
    println!("Andy suffers the consequences");
    
    println!("This is Mike");
    println!("Mike made a mistake");
    println!("Mike suffers the consequences");
    

    This works, but it does not scale. Changing the wording means editing every group. Going from 3 students to 30 means copying and editing 27 more lines, and every copy is a place to make a typo.

    One function with a parameter

    The part that changes becomes a parameter, and the part that stays the same goes in the function body. You write the apology once and call it once per student:

    fn print_message(name: &str) {
        println!("This is {}", name);
        println!("{} made a mistake", name);
        println!("{} suffers the consequences", name);
    }
    
    fn main() {
        print_message("Andy");
        print_message("Mike");
        print_message("Sally");
    }
    

    Now each change has one home:

    • To change who apologizes, change the arguments in the calls.
    • To change what the apology says, change the body of the function. Every call picks up the new text.

    Note that the same parameter name appears three times in the body. A parameter can be used as often as needed, and each use sees the same value for that call.

    More than one parameter

    When two things vary, use two parameters. Arguments are matched to parameters by position, and each parameter has its own type. In the exercise, the function needs both a name and a programming language, and both are owned String values, written name: String, language: String.

    Where each change lives

    Consider the second version of the apology, which says This is the apology of {} and combines two sentences into one line. In the repeated version you would rewrite all three groups. With the function, you edit the body once, and the calls for Andrei, Paul and Mary stay exactly as they were. Arguments describe who, and the body describes what. Keeping those two apart is the main reason functions take parameters at all.

    The body can also use a parameter more than once in a single println!. A format string with two placeholders, "{} made a mistake and so {} suffers the consequences", takes the argument name twice, once for each {}.

    The exercise

    The task is to write introduce_yourself, which prints two lines, and then call it for John and for Mary.

    1. Define the function above mainFunction with two String parameters, name and language. Function names are snake_case in Rust, so it is introduce_yourself.
    2. Print the name with println!("My name is {}", name). The {} placeholder is replaced by the next argument.
    3. Print the language on the next line with println!("I code in {}", language).
    4. Introduce John by calling the function with "John".to_string() and "Python".to_string(). A literal is a &str, and the parameters are String, so each argument needs the conversion.
    5. Introduce Mary with a second call using "Mary" and "JavaScript". Only the arguments change.
    // Function goes here:
    fn introduce_yourself(name: String, language: String) {
        println!("My name is {}", name);
        println!("I code in {}", language);
    }
    
    fn mainFunction() {
        // Introduce John:
        introduce_yourself("John".to_string(), "Python".to_string());
    
        // Introduce Mary:
        introduce_yourself("Mary".to_string(), "JavaScript".to_string());
    }
    

    The two calls print:

    My name is John
    I code in Python
    My name is Mary
    I code in JavaScript
    

    Gotchas

    • Argument order. Swapping the two arguments in a call compiles here, because both parameters are String, but it prints "My name is Python". The compiler can catch a swap only when the types differ.
    • Forgetting .to_string(). Passing a bare "John" fails with a type mismatch: expected String, found &str.
    • Parameters that grow. If a function ends up with many parameters of the same type, mixing up the order becomes easy. That is a sign to group related values, which later chapters cover.
    • The name mainFunction. It is not snake_case. The compiler only warns about it, and the program still builds.

    Key takeaways

    • Repeated code that differs only in some values belongs in a function, with those values as parameters.
    • Write the shared logic once, so each future change happens in one place.
    • Calls supply the arguments: different arguments, different output, same function.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free