Open In App

Rust – Closure as an Input Parameter

Last Updated : 22 Nov, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

In Rust, Closures can be taken as input for the parameters. Closures are functions that wrap up functions for reusable purposes, which help capture variables in the enclosing environment. Closures are closed over when used in functions and for a single expression elimination ({ }) is used. The closure arguments are written between the pipes (|), and the body is an expression.

Example 1:

Rust




// Rust example  of a closure
#![allow(unused_variables)]
fn main() {
let closure_variable = |x: i32| x * 10;
  
assert_eq!(100,closure_variable(10));
}


Output:

 

 

This program asserts whether the expression x* 10 = 100 or not when we pass the closure as a parameter in the expression. Here, the closure variable is declared as closure_variable and it references x (which is a 32-bit type). Now, we use the assert_eq! macro to validate whether the expression is true or false. If the assertion fails, Rust panics

Example 2: 

Rust




// Rust code
#![allow(unused_variables)]
fn main() {
let closure_variable = |x: i32| x * 10;
  
assert_eq!(90,closure_variable(10));
// println!("{:?}",plus_one);
}


Output:

 

While accepting closures as input parameters, the closure’s type is annotated with traits.

Before proceeding with the example, there are some terms related to traits:

  • Fn refers to closures that use captured value by reference
  • FnOnce refers to the closure that is used by capture by value.

Example 3:

Rust




// Rust code for Functions With Closure as Parameter
fn gfg<G>(f: G) where
      
    G: FnOnce() {
  
    f();
}
#[allow(dead_code)]
  
fn apply_function<G>(f: G) -> i32 where
    G: Fn(i32) -> i32 {
    f(3)
}
  
fn main() {
    use std::mem;
  
    let string_one = "Courses";
    let mut string_two = "GFG".to_owned();
    let value = || {
        
        // `greeting` is by reference: requires `Fn`.
        println!("GFG {}.", string_one);
        string_two.push_str("Practice");
        println!("Practising Coding on {}.", string_two);
         
        mem::drop(string_two);
    };
    gfg(value);
}


Output:

 

Explanation:

In this example, we have declared Fn and FnOnce as the two traits. Here, <G> refers to G which is a Generic type parameter. gfg is declared as a function that takes a closure argument and calls it. The closure G: FnOne does not take any input parameters and therefore does not return anything also at the same time. The function apply_funvyion takes a closure of a 32-bit integer and returns it as well. The std::mem is used for the management of memory and it provides basic functions that deals with memory. We have declared two strings string_one and string_two (which are mutable). string_two is mutable in nature and it is a noncopy type and the to_owned is a borrowed concept that is responsible for borrowing data. Now, we have declared a variable named ‘value’ that captures the two variables string_one by reference and string_two by value. If we see the function closely, we can see that string_one requires a reference named ‘Fn’ and due to mutation string_two requires FnMit as a mutable reference so that it is captured. After our job is done, we drop ‘string_two’ using the std::mem so that string_two is captured by value which in turn requires Fn) once again. Lastly, call the function gfg and pass ‘value’ as a closure.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads