Rust 中与闭包和生命周期作斗争

2024-02-08

我正在尝试将一些基准测试从 F# 移植到 Rust。 F# 代码如下所示:

let inline iterNeighbors f (i, j) =
  f (i-1, j)
  f (i+1, j)
  f (i, j-1)
  f (i, j+1)

let rec nthLoop n (s1: HashSet<_>) (s2: HashSet<_>) =
  match n with
  | 0 -> s1
  | n ->
      let s0 = HashSet(HashIdentity.Structural)
      let add p =
        if not(s1.Contains p || s2.Contains p) then
          ignore(s0.Add p)
      Seq.iter (fun p -> iterNeighbors add p) s1
      nthLoop (n-1) s0 s1

let nth n p =
  nthLoop n (HashSet([p], HashIdentity.Structural)) (HashSet(HashIdentity.Structural))

(nth 2000 (0, 0)).Count

它从潜在无限图中的初始顶点计算第 n 个最近邻壳。我在攻读博士学位期间使用类似的东西来研究非晶材料。

我花了很多时间尝试将其移植到 Rust,但失败了。我已经设法让一个版本工作,但只能通过手动内联闭包并将递归转换为具有本地可变变量的循环(yuk!)。

我尝试写iterNeighbors像这样的函数:

use std::collections::HashSet;

fn iterNeighbors<F>(f: &F, (i, j): (i32, i32)) -> ()
where
    F: Fn((i32, i32)) -> (),
{
    f((i - 1, j));
    f((i + 1, j));
    f((i, j - 1));
    f((i, j + 1));
}

我认为这是一个接受闭包(本身接受一对并返回单位)和一对并返回单位的函数。我似乎必须把事情加双括号:这是正确的吗?

我尝试编写这样的递归版本:

fn nthLoop(n: i32, s1: HashSet<(i32, i32)>, s2: HashSet<(i32, i32)>) -> HashSet<(i32, i32)> {
    if n == 0 {
        return &s1;
    } else {
        let mut s0 = HashSet::new();
        for &p in s1 {
            if !(s1.contains(&p) || s2.contains(&p)) {
                s0.insert(p);
            }
        }
        return &nthLoop(n - 1, s0, s1);
    }
}

请注意,我什至没有费心去打电话iterNeighbors yet.

我认为我正在努力使参数的生命周期正确,因为它们在递归调用中进行轮换。如果我愿意,我应该如何注释生命周期s2在之前被释放return我想要s1在返回时或进入递归调用时生存?

调用者看起来像这样:

fn nth<'a>(n: i32, p: (i32, i32)) -> &'a HashSet<(i32, i32)> {
    let s0 = HashSet::new();
    let mut s1 = HashSet::new();
    s1.insert(p);
    return &nthLoop(n, &s1, s0);
}

我放弃了,并将其写为while改为使用可变局部变量循环:

fn nth<'a>(n: i32, p: (i32, i32)) -> HashSet<(i32, i32)> {
    let mut n = n;
    let mut s0 = HashSet::new();
    let mut s1 = HashSet::new();
    let mut s2 = HashSet::new();
    s1.insert(p);
    while n > 0 {
        for &p in &s1 {
            let add = &|p| {
                if !(s1.contains(&p) || s2.contains(&p)) {
                    s0.insert(p);
                }
            };
            iterNeighbors(&add, p);
        }
        std::mem::swap(&mut s0, &mut s1);
        std::mem::swap(&mut s0, &mut s2);
        s0.clear();
        n -= 1;
    }
    return s1;
}

如果我手动内联闭包,这是可行的,但我不知道如何调用闭包。理想情况下,我希望在这里进行静态调度。

The main那么函数是:

fn main() {
    let s = nth(2000, (0, 0));
    println!("{}", s.len());
}

那么...我做错了什么? :-)

另外,我只用过HashSet在 F# 中,因为我认为 Rust 不提供纯函数式Set具有高效的集合论运算(并集、交集和差集)。我的假设正确吗?


我认为这是一个接受闭包(本身接受一对并返回单位)和一对并返回单位的函数。我似乎必须把事情加双括号:这是正确的吗?

您需要双括号,因为您要向闭包传递一个 2 元组,它与您的原始 F# 代码相匹配。

我认为我正在努力使参数的生命周期正确,因为它们在递归调用中进行轮换。如果我希望 s2 在返回之前被释放并且我希望 s1 在返回时或进入递归调用时生存,我应该如何注释生命周期?

问题是您正在使用对HashSet当你应该使用HashSet直接。您的签名nthLoop已经是正确的;你只需要删除一些出现的&.

解除分配s2, 你可以写drop(s2)。请注意,Rust 没有保证尾部调用,因此每个递归调用仍会占用一点堆栈空间(您可以使用mem::size_of https://doc.rust-lang.org/std/mem/fn.size_of.html函数),但是drop调用将清除堆上的数据。

调用者看起来像这样:

同样,您只需删除&'s here.

请注意,我什至还没有考虑对 iterNeighbors 的调用。


如果我手动内联闭包,这是可行的,但我不知道如何调用闭包。理想情况下,我希望在这里进行静态调度。

Rust 中有三种类型的闭包:Fn https://doc.rust-lang.org/stable/std/ops/trait.Fn.html, FnMut https://doc.rust-lang.org/stable/std/ops/trait.FnMut.html and FnOnce https://doc.rust-lang.org/stable/std/ops/trait.FnOnce.html。它们的类型不同self争论。这种区别很重要,因为它对允许闭包执行的操作以及调用者如何使用闭包施加了限制。 Rust 书中有关于闭包的一章 https://doc.rust-lang.org/stable/book/closures.html这已经很好地解释了这一点。

你的闭包需要改变s0。然而,iterNeighbors被定义为期望Fn关闭。你的关闭无法执行Fn因为Fn收到&self,但要变异s0, 你需要&mut self. iterNeighbors不能用FnOnce,因为它需要多次调用闭包。因此,您需要使用FnMut.

另外,没有必要通过引用来传递闭包iterNeighbors。你可以直接按值传递;对闭包的每次调用只会借用闭包,而不会消耗它。

另外,我只在 F# 中使用 HashSet,因为我假设 Rust 不提供具有高效集合论操作(并集、交集和差集)的纯函数集。我的假设正确吗?

标准库中没有纯函数集实现(也许有一个)crates.io https://crates.io/?)。虽然 Rust 支持函数式编程,但它也利用其所有权和借用系统来使命令式编程更安全。功能集可能会强制使用某种形式的引用计数或垃圾收集,以便跨集共享项目。

然而,HashSet https://doc.rust-lang.org/std/collections/struct.HashSet.html确实实现了集合论运算。有两种使用它们的方法:迭代器(difference https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.difference, symmetric_difference https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.symmetric_difference, intersection https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.intersection, union https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.union),它延迟生成序列,或运算符 (|, &, ^, -,如所列特征实现HashSet https://doc.rust-lang.org/std/collections/struct.HashSet.html#implementations),它生成包含源集中值的克隆的新集。


这是工作代码:

use std::collections::HashSet;

fn iterNeighbors<F>(mut f: F, (i, j): (i32, i32)) -> ()
where
    F: FnMut((i32, i32)) -> (),
{
    f((i - 1, j));
    f((i + 1, j));
    f((i, j - 1));
    f((i, j + 1));
}

fn nthLoop(n: i32, s1: HashSet<(i32, i32)>, s2: HashSet<(i32, i32)>) -> HashSet<(i32, i32)> {
    if n == 0 {
        return s1;
    } else {
        let mut s0 = HashSet::new();
        for &p in &s1 {
            let add = |p| {
                if !(s1.contains(&p) || s2.contains(&p)) {
                    s0.insert(p);
                }
            };
            iterNeighbors(add, p);
        }
        drop(s2);
        return nthLoop(n - 1, s0, s1);
    }
}

fn nth(n: i32, p: (i32, i32)) -> HashSet<(i32, i32)> {
    let mut s1 = HashSet::new();
    s1.insert(p);
    let s2 = HashSet::new();
    return nthLoop(n, s1, s2);
}

fn main() {
    let s = nth(2000, (0, 0));
    println!("{}", s.len());
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust 中与闭包和生命周期作斗争 的相关文章

随机推荐

  • 有没有办法找到重复的单词?

    我正在尝试找到 制作一个程序来查找 Excel 中所有重复的单词 例如 在 A1 中的 某人 在 A2 中的 某人 等 但我会多次出现 某人 或另一个单词 我需要将这些信息压缩在一起 但我需要以一种我不这样做的方式来做到这一点无法手动搜索来
  • 在开发中如何向 Django 提供 CSS?

    我已经阅读了所有文档 但它对我来说没有意义 我运行了collectstatic 我在我的应用程序和项目目录中设置了 static 目录 我将STATIC URL和STATIC ROOT添加到我的settings py文件中 但我不知道如何知
  • 尝试快速将协议添加到类签名中

    我正在尝试快速创建应用内购买 在我的班级签名中 我有以下内容 class ViewController UIViewController UITextFieldDelegate UIAlertViewDelegate SKStoreProd
  • 在 Tensorboard 投影仪中可视化 Gensim Word2vec 嵌入

    我只看到了几个提出这个问题的问题 但没有一个有答案 所以我想我不妨尝试一下 我一直在使用 gensim 的 word2vec 模型来创建一些向量 我将它们导出为文本 并尝试将其导入到嵌入投影仪的张量流实时模型中 一个问题 没用 它告诉我张量
  • nginx 背后的 ASP.NET 5

    我在 Nginx 服务器后面有一个 ASP NET 5 MVC6 应用程序 充当反向代理 它的配置是 server listen 80 server name example com location proxy pass http loc
  • 使用 Mockito 和 PowerMockito 模拟类对象

    是否可以使用 Mockito 和 或 PowerMockito 模拟类对象 就像是 Class
  • Java泛型如何接受泛型参数中的任何派生类型

    在下面2行代码中 HashMap
  • Eclipse 如何终止正在运行的程序?

    在 Eclipse 中 当您运行程序时 有一个漂亮的红色方形按钮可以停止它 我想知道这是如何做到的 Eclipse 是否只是残酷地杀死相应的进程 或者在温和地要求它终止自身或其他什么之前对进程状态进行一些很好的安全验证 是的 Eclipse
  • Docker postgres 无效的主检查点记录

    我一直在尝试让 postgres 在 Docker 在 Windows 上 中运行并具有持久数据存储 并认为我终于拥有了它 但现在当我尝试启动容器时 出现以下错误 LOG invalid primary checkpoint record
  • 是否可以将自定义元数据添加到 Lucene 字段?

    我已经到了需要存储一些有关 Lucene Net 索引中特定字段来自何处的附加数据的地步 具体来说 我想在将字段添加到文档时将 guid 附加到文档的某些字段 并在从搜索结果中获取文档时再次检索它 这可能吗 Edit 好吧 让我举个例子来澄
  • 如何动态更改引导程序模态体

    所以我将 Bootstrap 模态定义为 div class modal fade div class modal dialog modal sm div class modal content div class modal header
  • 如何在Android应用程序中读取和使用网站内容

    我实际上必须在 Android 应用程序中阅读和使用某些网站的内容 到目前为止 我主要使用两种不同的代码来获取网站的内容 但它们对我不起作用 public static String connect String url String re
  • 将 django 默认 pk 与 AutoField 更改为 BigAutoField

    我的模型有一个带有 AutoField 整数 的默认 pk 但后来我发现我需要使用 BigAutoField 然后我还有引用学生模型的其他模型的数据 我如何将 pk 字段更改为 BigAutoField 并反映在其他引用模型上 class
  • 当我尝试使用 vue js 显示 JSON 数据时,Selectpicker 不起作用?

    当我写 selectpicker selectpicker refresh 时在控制台中它正在加载 我应该在哪里提供此代码 我的 HTML 代码是
  • 错误 1045 (28000):用户“root”@“localhost”的访问被拒绝

    所以我第一次安装了MySQL应用程序 首先我看到命令行客户端没有打开 所以我寻找解决方案 他们说我必须进入 bin 目录并手动运行它 在我运行cmd之后mysql uroot p运行它并输入密码 它给了我错误 错误 1045 28000 用
  • 剪刀石头布 - Python 3 - 初学者

    我想模拟一个石头剪刀布游戏 这就是我到目前为止所拥有的 它不允许我在其中输入字母scoregame功能 我怎样才能解决这个问题 def scoregame player1 player2 if player1 R and player2 R
  • 防止选项卡循环浏览地址栏

    我意识到这可能是一个可访问性问题 最好不要管它 但我想弄清楚是否可以阻止选项卡在选项卡循环中访问地址栏 我的应用程序有另一种循环输入区域的方法 但许多新用户本能地尝试使用该选项卡 但它无法按预期工作 这是一个通用的 jquery 实现 您不
  • Selenium Instagram 机器人 - 单击“喜欢”按钮

    我已经编写了一个程序来访问 Instagram 探索页面 并喜欢前六张照片 现在 我正在使用这种相当复杂的方法来查找 喜欢 按钮 我更愿意将其格式化为 单击登录按钮 部分 到目前为止 我已经尝试检查各种元素 但我无法确定正确的元素以使其唯一
  • Chart.js 圆环图大小调整

    我在用着ng2 图表 https github com valor software ng2 charts在 Angular 项目中 我有该项目的两个版本 当前的生产版本是旧版本 并且使用旧版本的 ng2 charts 以及扩展的 Char
  • Rust 中与闭包和生命周期作斗争

    我正在尝试将一些基准测试从 F 移植到 Rust F 代码如下所示 let inline iterNeighbors f i j f i 1 j f i 1 j f i j 1 f i j 1 let rec nthLoop n s1 Ha