如何通过 WebAssembly 将 Rust 闭包返回给 JavaScript?

2023-11-30

的评论关闭.rs非常棒,但是我无法让它从 WebAssembly 库返回闭包。

我有一个这样的函数:

#[wasm_bindgen]
pub fn start_game(
    start_time: f64,
    screen_width: f32,
    screen_height: f32,
    on_render: &js_sys::Function,
    on_collision: &js_sys::Function,
) -> ClosureTypeHere {
    // ...
}

在该函数内部我做了一个闭包,假设Closure::wrap是拼图的一部分,复制自closure.rs):

let cb = Closure::wrap(Box::new(move |time| time * 4.2) as Box<FnMut(f64) -> f64>);

我如何返回这个回调start_game以及应该做什么ClosureTypeHere be?

这个想法是start_game将创建本地可变对象 - 例如相机,并且 JavaScript 端应该能够调用 Rust 返回的函数来更新该相机。


这是一个很好的问题,而且也有一些细微差别!值得呼吁的是闭包示例 in the wasm-bindgen指南(以及关于将闭包传递给 JavaScript 的部分),如果有必要的话,最好也能做出贡献!

不过,为了让您开始,您可以执行以下操作:

use wasm_bindgen::{Closure, JsValue};

#[wasm_bindgen]
pub fn start_game(
    start_time: f64,
    screen_width: f32,
    screen_height: f32,
    on_render: &js_sys::Function,
    on_collision: &js_sys::Function,
) -> JsValue {
    let cb = Closure::wrap(Box::new(move |time| {
        time * 4.2
    }) as Box<FnMut(f64) -> f64>);

    // Extract the `JsValue` from this `Closure`, the handle
    // on a JS function representing the closure
    let ret = cb.as_ref().clone();

    // Once `cb` is dropped it'll "neuter" the closure and
    // cause invocations to throw a JS exception. Memory
    // management here will come later, so just leak it
    // for now.
    cb.forget();

    return ret;
}

返回值上面只是一个普通的 JS 对象(这里作为JsValue),我们用Closure您已经见过的类型。这将允许您快速将闭包返回给 JS,并且您也可以从 JS 调用它。

您还询问过如何存储可变对象等,这都可以通过普通的 Rust 闭包、捕获等来完成。例如FnMut(f64) -> f64上面是 JS 函数的签名,它可以是任何类型的集合,例如FnMut(String, MyCustomWasmBindgenType, f64) -> Vec<u8>如果你真的想要的话。要捕获本地对象,您可以执行以下操作:

let mut camera = Camera::new();
let mut state = State::new();
let cb = Closure::wrap(Box::new(move |arg1, arg2| { // note the `move`
    if arg1 {
        camera.update(&arg2);
    } else {
        state.update(&arg2);
    }
}) as Box<_>);

(或类似的东西)

这里的camera and state变量将由闭包拥有并同时被删除。有关仅关闭的更多信息可以在 Rust 书中找到.

这里还值得简要介绍一下内存管理方面。在里面 上面的例子我们正在调用forget()它会泄漏内存,如果多次调用 Rust 函数,这可能会成为一个问题(因为它会泄漏大量内存)。这里的根本问题是在创建的 JS 函数对象引用的 WASM 堆上分配了内存。理论上,每当 JS 函数对象被 GC 时,就需要释放分配的内存,但我们无法知道这种情况何时发生(直到WeakRef exists!).

与此同时,我们选择了替代策略。相关的内存是 每当Closure类型本身被删除,提供 确定性破坏。然而,这使得工作变得困难,因为我们需要手动确定何时删除Closure. If forget不适合您的用例,一些放弃的想法Closure are:

  • 首先,如果它是一个仅调用一次的 JS 闭包,那么您可以使用Rc/RefCell删除Closure在闭合本身内部(使用一些内部 可变性恶作剧)。我们也应该最终 提供原生支持 为了FnOnce in wasm-bindgen还有!

  • 接下来,您可以向 Rust 返回一个辅助 JS 对象,该对象有一个手册free方法。例如一个#[wasm_bindgen]- 带注释的包装器。这个包装器将 然后需要在合适的时候在JS中手动释放。

如果你能熬过来的话forget是迄今为止最容易做的事情 现在看来,但这绝对是一个痛点!我们等不及了WeakRef存在 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何通过 WebAssembly 将 Rust 闭包返回给 JavaScript? 的相关文章

随机推荐

  • 有没有办法阻止 VB6 编译器打乱文件内容?

    由于未知的原因 VB6 编译器通常喜欢重新排序 vbp 文件的内容和 frm 文件顶部的控件描述符块 描述表单上控件属性的代码 您在IDE 但您确实可以在文本编辑器中看到在版本控制中与先前版本进行比较时 在比较文件的修订版本时 这非常烦人并
  • 有没有一种算法可以告诉两个短语的语义相似度

    输入 短语 1 短语 2 输出 语义相似度值 0到1之间 或者这两个短语谈论同一件事的概率 您可能想查看这篇论文 基于语义网络和语料库统计的句子相似度 PDF 我已经实现了所描述的算法 我们的背景非常笼统 实际上是任何两个英语句子 我们发现
  • 如何在 SWI-Prolog 中扩展结果列表?

    length L 25 L G245 G248 G251 G254 G257 G260 G263 G266 G 269 如果我在长度谓词后使用 write L 那么解释器会打印列表两次 一次扩展 另一次不扩展 深度有限制 防止输出过长 您可
  • 使用 Ruby 对字符串中的字符进行转义

    给定以下格式的字符串 Posterous API 以这种格式返回帖子 s u003Cp u003E 我怎样才能将它转换为实际的ascii字符 这样s p 在 OSX 上 我成功地使用了Iconv iconv ascii java s 但一旦
  • 使用 Spring AOP 触发了哪个接口(扩展 CrudRepository)的删除方法?

    Repository public interface UserRepository extends JpaRepository
  • Visual Studio 不再打开 Winforms 的图形编辑器

    我正在构建非常小的 15 分钟应用程序 它可以帮助我和我的同事完成简单的日常业务工作 为此 我经常使用 WinForm 因为它非常快 只需制作一个带有 2 个文本框和一个提交按钮的窗口 不幸的是 最近我想我按下了一个按钮 图形编辑器将不再打
  • 如何在android中获取准确的UTC时间戳

    我不知道哪一个适合获取 UTC 时间 我的代码是 System currentTimeMillis 对于 java 安卓 国际化的结果正确吗 也许用户可以更改设备时间并且结果会有所不同 对UTC有影响吗 在Linux平台上 系统时钟应设置为
  • 在本地 NTFS 驱动器上查找回收站

    我正在尝试编写一些简单的代码 该代码将返回本地驱动器上回收站的目录 看起来很简单 谷歌上应该有一千个答案 还没找到 我发现 FAT 和 NTFS 驱动器具有不同的基本名称 RECYCLED 和 RECYCLER 我发现 回收站 是一个虚拟文
  • Kmeans 对 pandas 数据框中的每个组进行聚类并分配聚类

    我想通过使用 kmeans 聚类对组月的 X2 和 X3 进行聚类 我需要对两个变量进行聚类 另外 我想根据每个簇的平均值将簇 0 簇 1 和簇 2 分配为 强 平均 弱 最高意味着强簇 下面是我的示例数据集 df pd DataFrame
  • 如何将 JSON null 反序列化为 NullNode 而不是 Java null?

    注意 杰克逊 2 1 x 问题很简单 但到目前为止我找不到解决方案 我浏览了现有文档等 但找不到答案 基类是这样的 JsonTypeInfo use Id NAME include As PROPERTY property op JsonS
  • 使用自定义 Cordova 插件将本机 iOS 事件绑定到 webView

    我必须创建一个插件来捕获 iOS 应用程序的 Cordova webView 中发生的事件并触发应用程序本机部分中的操作 反之亦然 我已关注本教程它工作完美 当我尝试将其适应另一个应用程序时 我希望它比教程更通用 它从 webView 到本
  • mysql 查询 - 输出的日期格式?

    在我的表中 日期存储如下 2011 03 03T13 30 00 我正在尝试输出这样的日期 2011 年 3 月 3 日下午 1 30 我更愿意将其放入查询中 而不是使用 php 来格式化它 但我在这方面遇到了一些困难 尝试 DATE FO
  • R:有什么方法可以在 Windows 中自动更新我的 R 吗?

    是啊 我懒得去下载最新版本的包了 我想知道如何设置我的 R 或者是否有一些代码可以让我在 Windows 中自动更新我的 R 如有任何帮助 我们将不胜感激 也许这会帮助你解决你的问题 installing loading the packa
  • 如何以编程方式获取美国州际公路出口的纬度和经度?

    有没有办法使用开源地图 API Google Map API Microsoft Live Map API 来做到这一点 或者有没有办法从地图文件遍历道路和交叉路口 如果我购买商业地图数据 Thanks 编辑 开源或API 基于 opens
  • 如何在 React 中引用本地图像?

    如何从本地目录加载图像并将其包含在reactjs img src tag 我有一张图片叫one jpeg在与我的组件相同的文件夹中 我尝试了两者 img src one jpeg and img src 在我里面render功能正常 但是图
  • 为什么当类返回 Lambda 时反射不起作用

    我遇到了一种有点奇怪的行为 我使用注释来标记具有特定用途的某些类 然后使用 org reflections 库查找具有特定注释的所有类 然而 当一个类实现一个返回 lambda 函数的方法时 反射将不再找到带注释的类 类的签名没有改变 注释
  • 如何自定义 Jersey JAXB 序列化的 XML 输出

    我有一些 javax xml bind annotation Xml 带注释的类 用于 REST Web 服务 Jersey 设置在 Spring 管理的 Web 容器中 并且 Web 服务返回格式良好的 xml 我们使用 maven en
  • Joomla 登录重定向回上一页

    我有某些页面需要用户登录 Joomla 当他们单击这些页面的链接时 iframe 覆盖层中会出现一个登录框 一旦他们登录 我想将他们重定向回他们尝试登录的页面 但是 Joomla 似乎只允许用户重定向到登录表单参数中预定义的页面 有没有办法
  • 通过单独的任务更新 BindingSource 中的元素

    我有一个类 比如 Person 有一个 ID 和一个名字 此类正确实现了 INotifyPropertyChanged 补充 有些人要求Person类 我真正的问题是一个更复杂的类 我已将其简化为一个相当简单的 POCO 以确保这不是因为我
  • 如何通过 WebAssembly 将 Rust 闭包返回给 JavaScript?

    的评论关闭 rs非常棒 但是我无法让它从 WebAssembly 库返回闭包 我有一个这样的函数 wasm bindgen pub fn start game start time f64 screen width f32 screen h