You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中实现带参数的requestAnimationFrame循环?

在Rust中实现带参数的requestAnimationFrame循环

问题原因

你遇到的错误是因为当闭包通过move捕获非Copy/Clone类型的参数时,会获取参数的所有权,导致闭包只能被调用一次(仅实现FnOnce)。但requestAnimationFrame要求闭包必须实现FnMut(浏览器需要多次调用该闭包触发循环),且WasmClosure trait仅支持FnMut和Fn类型。

解决方案

使用Rc<RefCell<T>>(需要修改参数时)或Rc<T>(无需修改参数时)包装参数,通过引用计数共享所有权,避免闭包消耗参数的所有权,从而让闭包满足FnMut的要求。

示例1:传递可修改的参数(如计数器)

use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;

fn loop(arg: Rc<RefCell<u32>>) {
    // 使用并修改参数
    *arg.borrow_mut() += 1;
    println!("当前计数器值: {}", arg.borrow());

    // 克隆Rc,让闭包持有共享引用
    let arg_clone = Rc::clone(&arg);
    let closure = Closure::wrap(Box::new(move || {
        loop(arg_clone);
    }) as Box<dyn FnMut()>);
    
    web_sys::window().unwrap()
        .request_animation_frame(closure.as_ref().unchecked_ref())
        .unwrap();
    closure.forget();
}

// 启动循环
fn start_loop() {
    let counter = Rc::new(RefCell::new(0));
    loop(counter);
}

示例2:传递不可修改的参数

如果参数不需要修改,直接用Rc<T>即可,无需RefCell:

use std::rc::Rc;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;

fn loop(arg: Rc<String>) {
    println!("当前参数值: {}", arg);

    let arg_clone = Rc::clone(&arg);
    let closure = Closure::wrap(Box::new(move || {
        loop(arg_clone);
    }) as Box<dyn FnMut()>);
    
    web_sys::window().unwrap()
        .request_animation_frame(closure.as_ref().unchecked_ref())
        .unwrap();
    closure.forget();
}

// 启动循环
fn start_loop() {
    let message = Rc::new(String::from("RAF循环测试"));
    loop(message);
}

关键说明

  • Rc<T>:提供引用计数的共享所有权,克隆Rc只会增加引用计数,不会复制内部数据
  • RefCell<T>:在单线程环境下提供内部可变性,允许我们在共享引用的基础上修改数据
  • closure.forget():阻止Rust的所有权系统回收闭包,因为浏览器会持有闭包引用直到动画帧触发

内容的提问来源于stack exchange,提问作者CodingMaster239

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:47:30