高级函数和闭包
本节探讨了一些与函数和闭包相关的高级特性。 包括函数指针和返回闭包。
函数指针
我们已经讨论了如何将闭包传递给函数;您也可以将常规
功能对功能!当您想要传递
函数,而不是定义新的闭包。功能
coerce 强制转换为类型fn
(带小写 f),不要与Fn
Closure trait 的 Trait 中。这fn
type 称为函数指针。传递函数
with 函数指针将允许您将函数用作其他
功能。
指定参数为函数指针的语法类似于
闭包的 VALUE,如示例 19-27 所示,其中我们定义了一个函数add_one
这会在其参数中增加 1。函数do_twice
双人
parameters:指向任何采用i32
参数
并返回一个i32
和一个i32
价值。这do_twice
函数调用
功能f
两次,将arg
值,然后添加 two 函数调用
结果一起。这main
函数调用do_twice
替换为参数add_one
和5
.
文件名: src/main.rs
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}"); }
示例 19-27:使用fn
type 接受函数
pointer 作为参数
此代码打印The answer is: 12
.我们指定参数f
在do_twice
是一个fn
,它采用一个i32
并返回一个i32
.然后我们可以调用f
在do_twice
.在main
,我们可以将
函数名称add_one
作为第一个参数传递给do_twice
.
与闭包不同,fn
是一种类型而不是 trait,因此我们指定fn
作为
parameter 类型,而不是使用
的Fn
traits 作为 trait bound 进行绑定。
函数指针实现了所有三个闭包特征 (Fn
,FnMut
和FnOnce
),这意味着您始终可以将函数指针作为
需要闭包的函数。最好使用泛型
type 和其中一个闭包 trait 的 set,以便你的函数可以接受
函数或闭包。
也就是说,一个你只想接受的例子fn
而不是
闭包是指与没有闭包的外部代码交互时: C
函数可以接受函数作为参数,但 C 没有闭包。
举个例子,说明你可以使用内联定义的闭包或命名的
函数,让我们看看map
方法由Iterator
trait 中。要使用map
函数将
numbers 转换为字符串向量,我们可以使用闭包,如下所示:
fn main() { let list_of_numbers = vec![1, 2, 3]; let list_of_strings: Vec<String> = list_of_numbers.iter().map(|i| i.to_string()).collect(); }
或者我们可以将函数命名为map
而不是 Closure 的
喜欢这个:
fn main() { let list_of_numbers = vec![1, 2, 3]; let list_of_strings: Vec<String> = list_of_numbers.iter().map(ToString::to_string).collect(); }
请注意,我们必须使用我们之前讨论的完全限定语法
在 “Advanced Traits” 部分中,因为
有多个名为to_string
.在这里,我们使用to_string
函数定义在ToString
trait 中,标准的
library 已实现的任何类型的Display
.
回想一下本章的“枚举值”部分 6 中,我们定义的每个枚举变体的名称也成为初始化器 功能。我们可以将这些初始化器函数用作函数指针,这些函数 实现 Closure trait,这意味着我们可以指定初始化器 函数作为接受闭包的方法的参数,如下所示:
fn main() { enum Status { Value(u32), Stop, } let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect(); }
在这里,我们创建Status::Value
实例u32
范围内的值
那map
通过使用Status::Value
.
有些人喜欢这种风格,有些人喜欢使用闭包。他们
编译为相同的代码,因此请使用您更清楚的样式。
返回闭包
闭包由 trait 表示,这意味着您不能返回闭包
径直。在大多数情况下,您可能希望返回特征,您可以改为返回 trait
使用实现 trait 的具体类型作为
功能。但是,你不能用 Closure 来做到这一点,因为它们没有
可返回的 concrete 类型;不允许使用该功能
指针fn
作为返回类型。
以下代码尝试直接返回一个闭包,但它不会编译:
fn returns_closure() -> dyn Fn(i32) -> i32 {
|x| x + 1
}
编译器错误如下:
$ cargo build
Compiling functions-example v0.1.0 (file:///projects/functions-example)
error[E0746]: return type cannot have an unboxed trait object
--> src/lib.rs:1:25
|
1 | fn returns_closure() -> dyn Fn(i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
1 | fn returns_closure() -> impl Fn(i32) -> i32 {
| ~~~~
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
1 ~ fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
2 ~ Box::new(|x| x + 1)
|
For more information about this error, try `rustc --explain E0746`.
error: could not compile `functions-example` (lib) due to 1 previous error
该错误引用了Sized
又是 trait!Rust 不知道有多少空间
它需要存储 closure。我们之前看到了这个问题的解决方案。
我们可以使用 trait 对象:
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
这段代码编译得很好。有关 trait 对象的更多信息,请参阅 部分“使用允许不同 类型”。
接下来,让我们看看宏!
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准