使用闭包优化 Rust 代码:环境捕获

函数式编程的概念,即函数采用参数的类型或返回函数类型,形成了对 Rust 中闭包的更广泛讨论,这对于今天的开发人员来说很重要。

闭包是类似于函数的匿名构造,可以作为参数传递、存储在变量中或作为命名函数的值返回。

在本文中,我们将探索和了解Rust中的闭包及其相关概念——例如,在 Rust 中使用带有迭代器的闭包,或者move关键字如何获取从闭包环境中捕获的值的所有权。我们将检查 Rust 中使用闭包捕获环境的关键方面,并使用示例演示如何使用闭包来优化代码。

跳跃前进:

  • Rust 中的闭包与函数句法身体返回类型数据类型环境捕捉

  • 闭包语法

  • 闭包类型推断和注解

  • 在 Rust 中使用闭包捕获环境

  • 闭包作为函数的参数

  • 使用带有迭代器的闭包来处理集合

Rust 中的闭包与函数

在 Rust 中,闭包和函数是两种不同类型的代码块,从 Windows 的右键单击菜单中编辑和删除不需要的应用程序用于不同的目的。

以下是您需要了解 Rust 中闭包和函数之间的主要区别:

句法

Rust 定义闭包和函数的语法略有不同。

闭包使用语法,其中参数在垂直管道 ( ) 之间传递,Logmein Express 让您轻松共享电脑屏幕主体包含在大括号 ( ) 之间。|parameters| -> return_type { body }||{}

另一方面,函数使用语法,其中参数在括号 ( ) 之间传递,如何使用栅栏整理和整理桌面返回类型在箭头 ( ) 之后指定。fn name(parameters: type) -> return_type { body }()->

身体

闭包的主体可以是单个语句或多个语句。

如果闭包由单个语句组成,则大括号是可选的;如何使用 FSL Launcher 清除桌面混乱但是,如果闭包由多个语句组成,则主体必须用大括号括起来。

相反,函数体必须始终括在花括号中,如何将网站 RSS 提要添加到 Windows 边栏无论它是由单个语句还是多个语句组成。

返回类型

在 Rust 中,闭包的返回类型是可选的——这意味着您不必指定闭包返回值的类型。

然而,函数的返回类型是强制性的——您必须使用语法指定函数返回的值类型。-> return_type

数据类型

您不必在 Rust 的闭包中指定参数的数据类型。但是,如何在 Windows Vista 和 Windows 7 中添加边栏小工具您必须使用类型参数语法指定函数中参数的数据类型。

环境捕捉

Rust 中的闭包可以从其环境中捕获变量,而函数则不能。32 位和 64 位 Windows 之间的区别以及如何选择这意味着闭包可以引用外部定义的变量。

闭包语法

让我们快速看一下闭包的语法定义以开始:

let closure = |...| {...}

|…|在上面的语法中,您可以在定义的部分内为闭包定义不同的参数,了解 Windows Vista 和 Windows 7 中的电源选项闭包的主体定义在该{…}部分内。

查看此代码块以了解我的意思:

fn main() {
  let closure = |x, y| { x + y };
  println!("{}", closure(1, 2)) // 3
}

就像函数一样,闭包是使用名称和两个括号执行的。

参数在管道语法之间定义,||. 此外,如何使用 Defraggler 对硬盘进行碎片整理您会注意到闭包是推断参数和返回类型的。

闭包类型推断和注解

上面的代码定义了一个名为“closure”的闭包,UltraSearch 是一个不错的 Windows 搜索工具它接受两个参数,x和y,并返回它们的和。闭包主体由单个语句组成,因为它是单个语句,所以没有用大括号括起来。x + y

在 Rust 中,闭包的类型是根据其参数和返回值的类型来推断的。在这种情况下,闭包接受两个 type 的参数i32并返回 type 的值i32,如何使用 PC Decrapifier 清理新计算机因此闭包的类型被推断为。|x: i32, y: i32| -> i32

有时,您可能希望使用闭包类型注释显式指定闭包类型;2 个有用的工具来添加项目和自定义 Windows 右键单击菜单当 Rust 编译器无法推断闭包类型或当你想为闭包指定更具体的类型时,这很有用。

要指定闭包类型注释,您可以使用语法如何使用 Ninite 在您的 PC 上批量安装程序. 例如:|parameters: types| -> return_type

fn main() {
  let closure: |x: i32, y: i32| -> i32 = |x, y| { x + y };
  println!("{}", closure(1, 2)) // 3
}

在这种情况下,闭包类型被显式指定为,System Explorer 是一个高效的任务管理器替代品它与推断的闭包类型相匹配。|x: i32, y: i32| -> i32

总的来说,闭包类型推断和注释允许您在 Rust 中指定闭包的类型,如何在 Windows Vista 中启用或禁用 Ctrl+Alt+Del 登录这对于确保类型安全和干净的代码很有用。

如前所述,闭包优于函数的优势之一是它们可以捕获变量并将其封装在定义它们的环境中。

让我们更详细地了解一下。

在 Rust 中使用闭包捕获环境

正如我们提到的,闭包可以从定义它们的环境中捕获值——闭包可以借用或获取这些周围值的所有权。

让我们构建一个代码场景,如何在 Vista 和 Windows 7 中添加额外的时钟我们可以在其中使用 Rust 执行一些环境捕获:

use std::collections::HashMap;

#[derive(Debug)]
struct Nft {
    tokens: Option<HashMap<String, u32>>
}

fn main() {
    let x = Nft {
        tokens: Some(HashMap::from([(String::from("string"), 32)]))
    };

    let slice = vec![1, 3, 5];

    let print_to_stdout = || {
        println!("Slice: {:?}", slice);
        if let Some(tokens) = &x.tokens {
           println!("Nft supply --> {:?}", tokens); 
        }
    };

    print_to_stdout();
    println!("{:?}", x);
    print_to_stdout();
}

这是您应该收到的输出:

Slice: [1, 3, 5]
Nft supply --> {"string": 32}
Nft { tokens: Some({"string": 32}) }
Slice: [1, 3, 5]
Nft supply --> {"string": 32}

在上面的代码片段中,使用 Windows 内存诊断工具检查内存问题我们定义了结构体x的一个实例Nft。我们还定义了一个slice变量——一种. 然后,我们定义了一个存储在变量中的闭包。Vec<i32>print_to_stdout

如果不将两个变量(x和slice)作为参数传递给闭包,在 Windows 中创建额外的分区,磁盘管理控制台我们仍然可以在print_to_stdout闭包中对它们进行不可变访问。

闭包捕获了对和变量的print_to_stdout不可变引用,因为它们是在与自身相同的作用域/环境中定义的。xslice

此外,因为print_to_stdout闭包只有一个对变量的不可变引用——AutoMouseClicker 使您的鼠标点击自动化这意味着它不能改变变量的状态——我们可以多次调用闭包来打印值。

我们还可以通过稍微调整代码片段来重新定义我们的闭包以获取对变量的可变引用,如下所示:

// --snip--
fn main() {
  // --snip--
  let mut slice = vec![1, 3, 5];

  let print_to_stdout = || {
        slice.push(11);
        // --snip--
        println!("Slice: {:?}", slice);
    };

    print_to_stdout();
    println!("{:?}", slice);
}

这是输出:

Slice: [1, 3, 5, 11]
[1, 3, 5, 11]

我们可以通过捕获对变量的可变引用来修改它的状态slice。

在执行闭包后print_to_stdout,解决因组策略错误 Windows 禁用的系统还原借用的引用立即返回,使我们可以将slice值打印到stdout。

在我们想要获取周围变量的所有权的情况下,我们可以move在闭包旁边使用关键字。

当我们在闭包中获得一个变量的所有权时,iPrint 节省打印机墨水并降低文档打印成本我们通常打算改变变量的状态。

使用我们之前的示例,让我们看一下它是如何工作的:

// --snip--
fn main() {
  // --snip--

  //Redefined the closure using move keyword
  let print_to_stdout = move || {
        slice.push(11);
        // --snip--
        println!("Slice: {:?}", slice);
    };

  print_to_stdout();
}

现在,我们已经明确地将变量移动到闭包中,使用我的密码箱在 Windows 中安全地隐藏文件夹取得了它们值的所有权。

如果您尝试像前面的代码块一样调用,您将收到一条错误消息,说明该变量由于在闭包中使用而被移动(如下所示)。println!("{:?}", slice);

闭包作为函数的参数

早些时候,我们解释了如何将闭包作为参数传递给函数,在 Windows 中使用 SDelete 永久删除文件甚至作为函数的值返回。

让我们探索如何使用函数的不同定义和特征边界来实现这些行为。

首先,让我们看看这三个Fn特征,由于函数签名定义或主体内容的性质,闭包将自动实现一个、两个或全部三个。如何使用 Recuva 恢复已删除的文件所有闭包至少都实现了该FnOnce特征。

以下是对这三个特征的解释:

  • FnOnce: 任何将捕获的变量返回到其调用环境的闭包都实现了这个特性

  • FnMut:此特征表示闭包可能会改变捕获的值并且不会将捕获的值作为返回值移出闭包的主体

在为项目中的不同用途定义闭包时,CloseAll 一键关闭所有打开的程序窗口这些规则可作为我们的指路明灯。

让我们通过实现上述特征之一来演示示例用例:

#[derive(Debug)]
enum State<T> {
    Received(T),
    Pending,
}

impl<T> State<T> {
    pub fn resolved<F>(self, f: F) -> T
    where F: FnOnce() -> T
    {
        match self {
            State::Received(v) => v,
            State::Pending => f(),
        }
    }
}

fn main() {
    let received_state = State::Received(String::from("LogRocket"));
    println!("{:?}", received_state.resolved(|| String::from("executed closure")));

    let pending_state = State::Pending;
    println!("{:?}", pending_state.resolved(|| String::from("executed closure")))
}

这是我们的输出:

"LogRocket"
"executed closure"

在上面的代码片段中,我们创建了一个示例枚举来假设表示具有已完成状态和状态State的网络调用。在枚举上,在 Windows 中设置家长控制的完整指南我们实现了一个函数来检查网络调用的状态并采取相应的行动。Received(T)Pending

查看函数签名,您会注意到f函数的参数是一个通用参数:一个FnOnce闭包。

使用 trait bounding ( ),我们定义了可能的参数值,对于这些值,means最多只能调用一次,不接受它自己的参数,并返回一个通用值。F: FnOnce() -> Tf,FT

如果我们有一个完成状态——变体——我们返回包含在完成状态中的值,如何在 Windows 中使用 Msconfig 禁用用户帐户控制 (UAC)就像我们对变量所做的那样。Received(T)received_state

当状态恰好是 时Pending,闭包参数将被调用,就像pending_state.

使用带有迭代器的闭包来处理集合

在本节中,您将了解闭包最常见的用例之一;使用 Karen 的目录打印机在 Windows 中打印文件和文件夹列表使用带有迭代器的闭包来处理集合中的一系列顺序数据。

迭代器模式对存储在 Rust 集合中的这个项目序列执行渐进式任务。

注意, 要进一步阅读迭代器,请查看Rust 文档。

让我们通过首先定义一个向量变量来进一步解释闭包如何与迭代器一起工作:

#[derive(PartialEq, Debug)]
struct MusicFile {
    size: u32,
    title: String,
}

fn main() {
    let files = vec![
            MusicFile {
                size: 1024,
                title: String::from("Last last"),
            },
            MusicFile {
                size: 2048,
                title: String::from("Influence"),
            },
            MusicFile {
                size: 1024,
                title: String::from("Ye"),
            },
        ];

        let max_size = 1024;

        let accepted_file_sizes: Vec<MusicFile> = files.into_iter().filter( |s| s.size == max_size).collect();

        println!("{:?}", accepted_file_sizes);
}

这是我们的输出:

[MusicFile { size: 1024, title: "Last last" }, MusicFile { size: 1024, title: "Ye" }]

在上面的代码片段中,我们使用可以在类型上调用的方法将files变量调整为迭代器。into_iterVec<T>

该into_iter方法创建迭代器类型的消费适配器类型。使用 7Plus 获得额外的 Windows 调整和快捷方式这个迭代器将每个值移出files变量(从开始到结束),这意味着我们不能在调用变量后使用它。

我们直接在filter函数内部定义它以调用闭包作为参数。适用于 Windows 7 和 Vista 的终极 Windows Tweaker然后,我们使用最后一个函数调用,消费迭代器并将其转换回 Rust 集合;在这种情况下,类型。collect()Vec<MusicFile>

结论

闭包是与普通函数或迭代器一起使用的类函数结构,用于处理存储在 Rust 集合中的顺序项。

您可以根据要将其用于何种上下文来实现特定的闭包类型——这使您可以灵活地获取捕获变量的所有权或借用对变量的引用,或者两者都不做!

根据您在 Rust 中的函数式编程需求,用于环境捕获的闭包可能会带来很大的好处,并使您的生活变得更加轻松。让我知道您在 Rust 中使用闭包和环境捕获的经验!

猜你喜欢

转载自blog.csdn.net/weixin_47967031/article/details/129959996