Rust Function Signatures with Lifetimes

RustRustBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, we are introduced to function signatures with lifetimes in Rust, where any reference must have an annotated lifetime and any reference being returned must have the same lifetime as an input or be static. It is important to note that returning references without input is prohibited if it would result in returning references to invalid data. The examples provided demonstrate valid forms of functions with lifetimes, including functions with one input reference, functions with mutable references, functions with multiple elements and different lifetimes, and functions that return references that have been passed in as parameters.

Note: If the lab does not specify a file name, you can use any file name you want. For example, you can use main.rs, compile and run it with rustc main.rs && ./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("`Rust`")) -.-> rust/BasicConceptsGroup(["`Basic Concepts`"]) rust(("`Rust`")) -.-> rust/DataTypesGroup(["`Data Types`"]) rust(("`Rust`")) -.-> rust/FunctionsandClosuresGroup(["`Functions and Closures`"]) rust(("`Rust`")) -.-> rust/DataStructuresandEnumsGroup(["`Data Structures and Enums`"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("`Variable Declarations`") rust/BasicConceptsGroup -.-> rust/mutable_variables("`Mutable Variables`") rust/DataTypesGroup -.-> rust/integer_types("`Integer Types`") rust/DataTypesGroup -.-> rust/string_type("`String Type`") rust/DataTypesGroup -.-> rust/type_casting("`Type Conversion and Casting`") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("`Function Syntax`") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("`Expressions and Statements`") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("`Method Syntax`") subgraph Lab Skills rust/variable_declarations -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/mutable_variables -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/integer_types -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/string_type -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/type_casting -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/function_syntax -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/expressions_statements -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} rust/method_syntax -.-> lab-99205{{"`Rust Function Signatures with Lifetimes`"}} end

Functions

Ignoring [elision], function signatures with lifetimes have a few constraints:

  • any reference must have an annotated lifetime.
  • any reference being returned must have the same lifetime as an input or be static.

Additionally, note that returning references without input is banned if it would result in returning references to invalid data. The following example shows off some valid forms of functions with lifetimes:

// One input reference with lifetime `'a` which must live
// at least as long as the function.
fn print_one<'a>(x: &'a i32) {
    println!("`print_one`: x is {}", x);
}

// Mutable references are possible with lifetimes as well.
fn add_one<'a>(x: &'a mut i32) {
    *x += 1;
}

// Multiple elements with different lifetimes. In this case, it
// would be fine for both to have the same lifetime `'a`, but
// in more complex cases, different lifetimes may be required.
fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {
    println!("`print_multi`: x is {}, y is {}", x, y);
}

// Returning references that have been passed in is acceptable.
// However, the correct lifetime must be returned.
fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x }

//fn invalid_output<'a>() -> &'a String { &String::from("foo") }
// The above is invalid: `'a` must live longer than the function.
// Here, `&String::from("foo")` would create a `String`, followed by a
// reference. Then the data is dropped upon exiting the scope, leaving
// a reference to invalid data to be returned.

fn main() {
    let x = 7;
    let y = 9;

    print_one(&x);
    print_multi(&x, &y);

    let z = pass_x(&x, &y);
    print_one(z);

    let mut t = 3;
    add_one(&mut t);
    print_one(&t);
}

Summary

Congratulations! You have completed the Functions lab. You can practice more labs in LabEx to improve your skills.

Other Rust Tutorials you may like