Ошибка вызова Clousure при создании обратного вызова с Clousure при событии ввода мыши в WASM-Bindgen Rust

У меня есть программа Rust, созданная на основе примера холста WASM-Bindgen. Я пытаюсь вызвать код Rust для каждого onmousemove события JavaScript для элемента Canvas. Мой код в настоящее время успешно создает событие DOM (как кажется). Однако при каждом срабатывании события консоль инструментов разработчика Firefox Developer Edition показывает ошибку:

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, 60, 6, "#444");
    
    manager.fill_rect_with_color(236, 236, 8, 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()));
}


person user2921779    schedule 28.08.2020    source источник
comment
Привет, это мистер Расс ;-). Вижу, у вас есть ответ на свой вопрос. Обычно в Stack Overflow любезно проголосовать за него / принять его, если он соответствует вашим требованиям, или прокомментировать его, если это не так. :-) Я уверен, что отвечающий будет признателен. :-)   -  person Russ J    schedule 31.08.2020


Ответы (1)


В предоставленном коде 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();

Взгляните на хороший ответ как избежать утечки памяти.

person MaxV    schedule 28.08.2020