Skip to content
Lesson 8 of 15

Step 1 of 5 · Reading · ~3 min

Learn

Functions and Ownership

Functions

By the end of this lesson you can write your own Rust functions with typed parameters and a return value, return a result without the return keyword, and build one function out of calls to another.

The shape of a function

fn double(x: i64) -> i64 {
    x * 2
}
  • fn double names the function. Names are snake_case; the compiler warns otherwise.
  • (x: i64) is the parameter list. Every parameter needs a type written out. Rust infers types inside a body, never in a signature: the signature is the contract callers rely on.
  • -> i64 is the return type, the type of the value the caller gets back.
  • The body is a block. Its last line, x * 2, is the value the function hands back.

Calling it looks like every other language: double(21) evaluates to 42, and println!("{}", double(21)); prints 42. Functions can be defined above or below main; order in the file does not matter.

Expressions, statements, and the semicolon

An expression produces a value (x * 2, double(5), an if with both branches). A statement does something and produces nothing; a trailing ; turns an expression into a statement. "Nothing" in Rust is a real type, written () and called unit.

The last expression of a block, written without a semicolon, is the block's value. Add the semicolon and the value is thrown away:

fn double(x: i64) -> i64 {
    x * 2;        // statement: the block's value is now ()
}
// error[E0308]: mismatched types
// expected `i64`, found `()`
// help: remove this semicolon

When you see expected i64, found (), look at the last line first. A function with no -> at all returns (), which is right for a function that only prints:

fn show(label: &str, value: i64) {
    println!("{} = {}", label, value);
}

return exists, and idiomatic Rust uses it for early exits, letting the final expression fall out of the bottom:

fn clamp_to_ten(x: i64) -> i64 {
    if x > 10 {
        return 10;
    }
    x
}
// clamp_to_ten(4) -> 4, clamp_to_ten(99) -> 10

Functions that call functions

A function body can call any other function, so small pieces combine into bigger ones. A rectangle's perimeter is two widths plus two heights:

fn perimeter(w: i64, h: i64) -> i64 {
    double(w) + double(h)
}

fn main() {
    show("perimeter", perimeter(3, 5));
}

Trace perimeter(3, 5): double(3) gives 6, double(5) gives 10, 6 + 10 is 16, and show prints perimeter = 16. Each call copies its integer arguments in; the callee changing its own parameter never touches the caller's variable.

The width trap

The parameter type decides how big a value can get. i32 stops at 2,147,483,647:

fn triple32(x: i32) -> i32 { x * 3 }
fn triple64(x: i64) -> i64 { x * 3 }
// triple32(1_000_000_000) -> panic: attempt to multiply with overflow
// triple64(1_000_000_000) -> 3000000000

Multiplying a number by itself grows fastest of all: anything above 46,340 squared no longer fits in an i32. Keep the i64 signatures you are given.

Common mistakes

  • Doubling instead of multiplying the value by itself. x * 2 and x + x give 4 for input 2, the only value where they agree with a square. For 7 they print 14 instead of 49.
  • Squaring the sum. Adding a and b first and then squaring gives (7 + -9)^2 = 4, not 49 + 81 = 130. The sum of squares is two separate squares added together.
  • Forgetting to square the second number inside the combined function, so 10 and 3 give 103 instead of 109.
  • Narrowing to i32. Changing a signature to i32 or casting with as i32 breaks on 3000000000, whose square is 9,000,000,000,000,000,000.

Your exercise

Fill in the bodies of square and sum_of_squares; the starter already reads both numbers and prints the three results. Each body returns its value as a final expression, and sum_of_squares should reuse square instead of repeating the arithmetic. The most likely slip is squaring the sum rather than summing the squares.

Up nextOwnership and BorrowingFunctions and Ownership

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…