mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 13:04:18 -06:00
almost finished ch20.4
This commit is contained in:
parent
e73197aa26
commit
e6bb4977b8
23
.obsidian/workspace.json
vendored
23
.obsidian/workspace.json
vendored
@ -10,20 +10,6 @@
|
||||
{
|
||||
"id": "de2ac5df5b921166",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Advanced Features.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "Advanced Features"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b24fe202609f5b35",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
@ -87,8 +73,7 @@
|
||||
"title": "Graph view"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 1
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
@ -231,12 +216,13 @@
|
||||
"command-palette:Open command palette": false
|
||||
}
|
||||
},
|
||||
"active": "b24fe202609f5b35",
|
||||
"active": "de2ac5df5b921166",
|
||||
"lastOpenFiles": [
|
||||
"Advanced Features.md",
|
||||
"Advanced Functions and Closures.md",
|
||||
"Advanced Types.md",
|
||||
"Advanced Traits.md",
|
||||
"Enums.md",
|
||||
"Advanced Functions and Closures.md",
|
||||
"Unsafe Rust.md",
|
||||
"Pattern Matching.md",
|
||||
"Places Patterns Can Be Used.md",
|
||||
@ -258,7 +244,6 @@
|
||||
"().md",
|
||||
"Smart Pointers.md",
|
||||
"Simultaneous Code Running.md",
|
||||
"Passing Data Between Threads.md",
|
||||
"minigrep/src/lib.rs",
|
||||
"does_not_compile.svg",
|
||||
"Untitled.canvas",
|
||||
|
@ -1 +1,106 @@
|
||||
# Advanced Functions and Closures
|
||||
This section includes some more advanced features including function pointers and returning closures.
|
||||
|
||||
## Function Pointers
|
||||
We have talked about how to pass closures to functions; you can also pass regular functions to functions.
|
||||
|
||||
This technique is useful when you want to pass a function that you have already defined rather than defining a new closure.
|
||||
|
||||
Functions coerce to the type `fn` (with a lowercase f), not to be confused with, not to be confused with the `Fn` closure trait.
|
||||
|
||||
The `fn` type is called a *function pointer*.
|
||||
|
||||
Passing function pointers will allow you to use functions as arguments to other functions.
|
||||
|
||||
The syntax for specifying that a parameter is a function pointer is similar to that of closures as shown below.
|
||||
|
||||
This shows that we have defined a function `add_one` that adds one to its parameter.
|
||||
|
||||
The function `do_twice` takes two parameters: a function pointer to any function takes an `i32` parameter and returns an `i32`, and one `i32` value.
|
||||
|
||||
The `do_twice` function calls the function `f` twice, passing it the `arg` value, then adds the two function call results together.
|
||||
|
||||
The `main` function calls `do_twice` with the arguments `add_one` and `5`.
|
||||
```rust
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
|
||||
f(arg) + f(arg)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let answer = do_twice(add_one, 5);
|
||||
|
||||
println!("The answer is: {answer}");
|
||||
}
|
||||
```
|
||||
Output
|
||||
```
|
||||
The answer is: 12
|
||||
```
|
||||
Here we specify that the parameter `f` in `do_twice` is an `fn` that takes one parameter of type `i32` and returns a `i32`.
|
||||
|
||||
We can then call `f` from the body of `do_twice`.
|
||||
|
||||
In `main` we can pass the function name `add_one` as the first arg to `do_twice`.
|
||||
|
||||
Unlike closures, `fn` is a type rather than a trait, so we need to specify `fn` as the parameter type directly rather than declaring a generic type parameter with one of the `Fn` traits as a trait bound.
|
||||
|
||||
Function pointers implement all three of the closure traits (`Fn`, `FnMut` and `FnOnce`).
|
||||
|
||||
This means that you can always pass a function pointer as an argument for a function that expects a closure.
|
||||
|
||||
It is best to write functions using a generic type and one of the closure traits so your functions can accept either functions or closures.
|
||||
|
||||
That being said, one example of where you would only want to accept `fn` and not closures is when interfacing with external code that doesn't have closures.
|
||||
|
||||
C functions can accept functions as arguments, but C doesn't have closures.
|
||||
|
||||
As an example of where you could use either a closure defined inline or a named function.
|
||||
|
||||
Lets look at a use of the `map` method provided by the `Iterator` trait in the std library.
|
||||
|
||||
To use the `map` function to turn a vector of numbers into a vector of strings, we could use a closure.
|
||||
|
||||
Like this:
|
||||
```rust
|
||||
let list_of_numbers = vec![1, 2, 3];
|
||||
let list_of_strings: Vec<String> =
|
||||
list_of_numbers.iter().map(|i| i.to_string()).collect();
|
||||
```
|
||||
We could have a function as the argument to `map` instead of the closure.
|
||||
|
||||
Like this:
|
||||
```rust
|
||||
let list_of_numbers = vec![1, 2, 3];
|
||||
let list_of_strings: Vec<String> =
|
||||
list_of_numbers.iter().map(ToString::to_string).collect();
|
||||
```
|
||||
Note, we must use the fully qualified syntax that we talked about earlier in ["Advanced Traits"](./Advanced%20Traits.md) section.
|
||||
|
||||
This is because there are multiple functions available named `to_string`.
|
||||
|
||||
Here we are using the `to_string` function defined in the `ToString` trait, which is in the std library has implemented for any type that implements `Display`.
|
||||
|
||||
Recall form the ["Enum values"]() section of Ch6 that the name of each enum variant that we define also becomes an initializer function.
|
||||
|
||||
We can use these initializer functions as function pointers that implement the closure traits, this means we can specify the initializer functions as arguments for methods that take closures.
|
||||
|
||||
Like this:
|
||||
```rust
|
||||
enum Status {
|
||||
Value(u32),
|
||||
Stop,
|
||||
}
|
||||
|
||||
let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect();
|
||||
```
|
||||
Here we creates `Status::Value` instances using each `u32` value in the range that `map` is called on by using the initializer function of `Status::Value`.
|
||||
|
||||
Some prefer to use this style, and some people prefer to use closures.
|
||||
|
||||
They compile to the same code, so use whatever style is clearer to you.
|
||||
|
||||
## Returning Closures
|
||||
|
Loading…
x
Reference in New Issue
Block a user