在WASM-Bindgen Rust中在鼠标输入事件上创建带有Clousure的回调时出现Clousure调用错误

问题描述

我有一个WASM-Bindgen "canvas" example分叉的Rust程序。我试图在onmousemove元素的每个JavaScript Canvas事件上调用一些Rust代码。我的代码当前成功创建了DOM事件(看来)。但是,在每次触发的事件中,Firefox开发人员版开发人员工具的控制台都会显示错误

Uncaught Error: closure invoked recursively or destroyed already

这是我的代码的一部分:

use std::f64;
use std::sync;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

mod canvas_manager;
use canvas_manager::CanvasManager;

#[wasm_bindgen(start)]
pub fn start() {
    let document = web_sys::window().unwrap().document().unwrap();
    let canvas = document.get_element_by_id("canvas").unwrap();
    let canvas: web_sys::HtmlCanvasElement = canvas
        .dyn_into::<web_sys::HtmlCanvasElement>()
        .map_err(|_| ())
        .unwrap();

    let manager = CanvasManager::new(canvas,480,480);

    manager.fill_rect_with_color(210,12,60,6,"#444");
    
    manager.fill_rect_with_color(210,462,"#444");
    
    manager.fill_rect_with_color(236,236,8,"#999");

    manager.clear_canvas();

    let xPos= sync::Arc::from(sync::Mutex::new(Box::new(0f64)));

    let xPosCloned = xPos.clone();

    let a = Closure::wrap(Box::new(move || {
        let mut xPosBox = xPosCloned.lock().unwrap();
        **xPosBox += 1f64;
        //web_sys::console::log_1(&JsValue::from_f64(2.5f64));
    }) as Box<dyn FnMut()>);

    manager.canvas.set_onmousemove(Some(a.as_ref().unchecked_ref()));
}

解决方法

所提供的代码a将在start()的末尾删除。

您可以通过a.forget()来解决此问题,但随后会引起内存泄漏。

let a = Closure::wrap(Box::new(move || {
    let mut xPosBox = xPosCloned.lock().unwrap();
    **xPosBox += 1f64;
    //web_sys::console::log_1(&JsValue::from_f64(2.5f64));
}) as Box<dyn FnMut()>);

manager.canvas.set_onmousemove(Some(a.as_ref().unchecked_ref()));
a.forget();

请看看不错的answer如何避免内存泄漏。