Go调用Rust编译的WASM函数返回多值时参数错误如何解决
问题根因
你遇到的got 2 expected 3 arguments报错,本质是Rust extern "C" ABI和WASM原生多值返回的适配问题:
当Rust的extern "C"函数返回非基础类型的复合值(比如你这里的(*mut u8, i32)元组)时,默认的C调用约定不会直接使用WASM原生多值返回特性,而是会自动添加一个隐式的输出指针参数作为函数的第一个入参,用来存储返回的复合值,所以原本2个入参的函数就变成了需要3个入参,你调用时只传了2个,就触发了参数数量不匹配的报错。
解决方案
方案1:强制Rust使用WASM原生多值返回(推荐)
你需要调整Rust侧的声明和编译参数,同时修正Go侧的配置加载逻辑:
- 先修改Rust代码,引入
wasm-bindgen依赖指定原生多值返回规则:
# Cargo.toml 新增依赖 [dependencies] wasm-bindgen = "0.2"
// Rust 函数代码修改 use wasm_bindgen::prelude::*; #[no_mangle] #[wasm_bindgen] pub extern "C" fn echo(ptr: *mut u8, length: usize) -> (*mut u8, i32) { // 原有逻辑不变 let newptr = get_ptr(); let newlength = get_length(); (newptr, newlength) }
- 编译时添加多值返回特性的编译参数:
RUSTFLAGS="-C target-feature=+multivalue" cargo wasi build
- 修正Go侧的Engine初始化逻辑,把你设置的多值返回配置传给Engine(你之前的代码只创建了配置但没有关联到Engine,配置并未生效):
// 修正后的Go侧初始化代码 config := wasmtime.NewConfig() config.SetWasmMultiValue(true) // 必须把配置传入Engine构造方法 engine := wasmtime.NewEngineWithConfig(config) store := wasmtime.NewStore(engine) linker := wasmtime.NewLinker(store) // 后续调用逻辑不变 result, err := server.funcs["echo"].Call(server.ptr, int32(len(recivedBytes))) check(err) res := result.([]wasmtime.Val) // 直接按索引取返回值即可 ptr := res[0].Int32() newLength := res[1].Int32()
方案2:适配Rust默认C ABI的隐式参数规则
如果你不想引入wasm-bindgen,也可以直接适配默认的隐式参数逻辑:
Go侧调用时提前在WASM内存中申请一块足够存储返回元组的空间(两个i32共8字节),把这块空间的指针作为第一个入参传给echo函数,后续再跟上原本的两个入参,调用完成后从你申请的内存空间里读取返回的指针和长度即可。
内容的提问来源于stack exchange,提问作者Hanif Tadjik
相关产品推荐
相关产品推荐

