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",
|
"id": "de2ac5df5b921166",
|
||||||
"type": "leaf",
|
"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": {
|
"state": {
|
||||||
"type": "markdown",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
@ -87,8 +73,7 @@
|
|||||||
"title": "Graph view"
|
"title": "Graph view"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"currentTab": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "vertical"
|
"direction": "vertical"
|
||||||
@ -231,12 +216,13 @@
|
|||||||
"command-palette:Open command palette": false
|
"command-palette:Open command palette": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "b24fe202609f5b35",
|
"active": "de2ac5df5b921166",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"Advanced Features.md",
|
"Advanced Features.md",
|
||||||
"Advanced Functions and Closures.md",
|
|
||||||
"Advanced Types.md",
|
"Advanced Types.md",
|
||||||
"Advanced Traits.md",
|
"Advanced Traits.md",
|
||||||
|
"Enums.md",
|
||||||
|
"Advanced Functions and Closures.md",
|
||||||
"Unsafe Rust.md",
|
"Unsafe Rust.md",
|
||||||
"Pattern Matching.md",
|
"Pattern Matching.md",
|
||||||
"Places Patterns Can Be Used.md",
|
"Places Patterns Can Be Used.md",
|
||||||
@ -258,7 +244,6 @@
|
|||||||
"().md",
|
"().md",
|
||||||
"Smart Pointers.md",
|
"Smart Pointers.md",
|
||||||
"Simultaneous Code Running.md",
|
"Simultaneous Code Running.md",
|
||||||
"Passing Data Between Threads.md",
|
|
||||||
"minigrep/src/lib.rs",
|
"minigrep/src/lib.rs",
|
||||||
"does_not_compile.svg",
|
"does_not_compile.svg",
|
||||||
"Untitled.canvas",
|
"Untitled.canvas",
|
||||||
|
@ -1 +1,106 @@
|
|||||||
# Advanced Functions and Closures
|
# 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