如何在Rust编写的WASM中导入WASM模块并传递String参数
问题原因
- 只有入参、返回值均为基础数值类型(如i32)的WASM导出函数,可以在无额外导入的前提下直接调用。涉及
String这类堆分配类型的函数,wasm-bindgen不会直接导出接收/返回原生JS值的函数,裸导出的是仅操作WASM内存的ABI层函数,参数和返回值都是代表内存指针、长度的整数值,直接传JS字符串不可能正常执行。 - 你实例化子WASM时传入了空导入对象,但包含堆操作的wasm-bindgen模块必须依赖一组导入的辅助函数(内存管理、字符串编解码、共享内存等)才能运行,空导入下这类函数根本不具备执行条件,自然返回undefined。
实现方案
方案1:使用wasm-bindgen原生跨模块导入(推荐)
这是稳定性最高、无需手动处理内存的方案:
- 正常编译
imported_lib,保留wasm-bindgen生成的JS粘合文件,不要直接嵌入裸WASM字节码。 - 在主库的Rust代码中通过
extern "C"块声明要调用的子模块函数,wasm-bindgen会自动生成跨模块的粘合代码,不需要手动写实例化逻辑、手动操作内存:
#[wasm_bindgen] extern "C" { fn hello(name: String) -> String; fn add(a: i32, b: i32) -> i32; }
- 构建时通过wasm-pack或对应WASM构建插件处理两个模块的依赖关系即可,调用时直接按普通Rust函数传入
String参数就能拿到正确返回值。
方案2:手动实例化并完成ABI转换(非必要不推荐)
如果必须手动嵌入子WASM字节码做动态加载,需要完成以下步骤:
- 实例化子WASM时不能传空导入对象,要把主模块导出的wasm-bindgen辅助函数、共享内存作为导入传给子模块,保证子模块的内存管理逻辑可以正常运行。
- 调用
hello前,先将传入的JS字符串编码为UTF-8字节数组,调用子模块导出的内存分配函数申请对应长度的WASM内存,把字节写入内存后,将返回的指针、字节长度作为两个i32参数传入ABI层的hello导出。 - 调用完成后,从返回的i32值中解析出结果字符串的指针和长度,从WASM内存中读取对应字节解码为JS字符串,最后调用内存释放函数回收对应内存,避免内存泄漏。
不同版本wasm-bindgen的ABI规则、辅助函数签名可能存在差异,手动编写内存转换逻辑会存在版本兼容问题,容易触发内存错误、未定义行为。
内容的提问来源于stack exchange,提问作者Arnold Daniels
相关产品推荐
相关产品推荐

