1. Definition and use of closures
The basic syntax of closure is as follows:
let closure = |Parameter list| expression;
For example, define a closure that takes an integer and returns its square:
let square = |x: i32| x * x;
You can call closures like calling a function:
let result = square(5); println!("5 The square is {}", result);
2. Capture variables in the environment
An important feature of closures is the ability to capture variables in their defined environment. Depending on the capture method, closures can be divided into three types:FnOnce
、FnMut
andFn
。
2.1 FnOnce: Obtain ownership
If the closure takes ownership of the environment variable, it can only be called once. For example:
let s = String::from("hello"); let consume = move || { println!("{}", s); // The ownership of s has been moved to the closure and cannot be used later}; consume(); // println!("{}", s); // Compilation error:s Ownership of the
In the above code,move
Keyword forced closure acquisitions
ownership ofs
No longer available outside the closure.
2.2 FnMut: Variable Borrow
If the closure captures environment variables in a mutable borrowed way, it can modify these variables. For example:
let mut count = 0; let mut increment = || { count += 1; println!("count: {}", count); }; increment(); increment();
Each callincrement
When closure,count
The values of each are increased by 1.
2.3 Fn: Immutable borrowing
If the closure captures environment variables in an immutable borrowed way, it can only read these variables and cannot modify them. For example:
let x = 5; let print_x = || { println!("x: {}", x); }; print_x();
In this example,print_x
Closures can only be readx
The value of , cannot be modified.
3. Type inference and annotation of closures
The Rust compiler will automatically infer the type of closure based on the usage of environment variables in the closure body. Normally, explicit annotations are not required. However, in some cases, it may be necessary to specify the type of closure explicitly:
let add_one = |x: i32| -> i32 { x + 1 };
In this example,add_one
It's an acceptancei32
Type parameter and returni32
Closure of type result.
4. Comparison of closures and functions
Although both closures and functions can accept parameters and return values, closures have the following unique features:
- Capture the environment: A closure can capture variables in its definition environment, but a function cannot.
- Type inference: The type of the closure can be automatically inferred by the compiler, while the parameter and return value types of the function need to be explicitly declared.
5. Practical application of closures
Closures are widely used in Rust, especially in scenarios related to iterators and concurrent programming. For example, use closures to filter a collection:
let numbers = vec![1, 2, 3, 4, 5]; let even_numbers: Vec<i32> = numbers.into_iter() .filter(|&x| x % 2 == 0) .collect(); println!("{:?}", even_numbers); // Output:[2, 4]
In this example,filter
The method accepts a closure as a parameter to filter out even numbers.
6. Summary
Closures are one of the powerful features in Rust that allow functions to capture and manipulate variables in their definition environment. By understanding the types and features of closures, developers can write more flexible and efficient code.
This is the article about the anonymous functions of the closure in Rust and the capture environment. For more related contents of the anonymous functions of Rust closure, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!