在Rust + WASM中返回二维向量的函数签名适配问题
解决wasm_bindgen嵌套Vec类型不兼容问题
wasm_bindgen 默认仅支持与JS原生类型直接映射的Rust类型(比如Vec<isize>可转为JS数组),但嵌套容器类型(如Vec<Vec<isize>>、Vec<Vec<(usize, usize)>>)没有默认的跨语言转换实现,因此会触发trait bound JsObject不满足的错误。以下是两种可行的解决方案:
方案一:使用JsValue手动序列化/反序列化
通过serde_json在Rust类型与JS值之间手动转换,适用于复杂嵌套结构:
- 添加依赖到
Cargo.toml:
[dependencies] wasm-bindgen = "0.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
- 修改函数实现:
use wasm_bindgen::prelude::*; use serde::{Deserialize, Serialize}; // 定义输入结构,用于解析JS传入的数据 #[derive(Debug, Deserialize)] struct FindInput { matrix: Vec<Vec<isize>>, threshold: usize, } // 定义输出结构,用于序列化为JS值 #[derive(Debug, Serialize)] struct FindOutput { result: Vec<Vec<(usize, usize)>>, } #[wasm_bindgen] pub fn find(input: JsValue) -> Result<JsValue, JsValue> { // 解析JS输入到Rust结构 let input = serde_json::from_value(input) .map_err(|e| JsValue::from_str(&format!("输入解析失败: {}", e)))?; // 原业务逻辑示例 let mut result = Vec::new(); for (row_idx, row) in input.matrix.iter().enumerate() { let mut coords = Vec::new(); for (col_idx, &val) in row.iter().enumerate() { if val as usize <= input.threshold { coords.push((row_idx, col_idx)); } } result.push(coords); } // 序列化结果为JS值返回 let output = FindOutput { result }; serde_json::to_value(output) .map_err(|e| JsValue::from_str(&format!("输出序列化失败: {}", e))) }
- JS端调用示例:
import { find } from './your_wasm_module'; const input = { matrix: [[1, 5, 3], [2, 4, 6]], threshold: 3 }; const result = await find(input); // result.result 为 [[[0,0], [0,2]], [[1,0]]]
方案二:启用wasm_bindgen的serde集成(更简洁)
通过启用wasm_bindgen的serde特性,让支持Serialize/Deserialize的Rust类型自动与JS类型互转:
- 修改
Cargo.toml依赖:
[dependencies] wasm-bindgen = { version = "0.2", features = ["serde"] } serde = { version = "1.0", features = ["derive"] }
- 调整函数签名与实现:
注意:直接使用元组(usize, usize)可能存在序列化兼容性问题,建议包装为结构体或数组:
use wasm_bindgen::prelude::*; use serde::{Deserialize, Serialize}; // 包装坐标类型,实现序列化/反序列化 #[derive(Debug, Serialize, Deserialize)] struct Coord(usize, usize); #[wasm_bindgen] pub fn find(matrix: Vec<Vec<isize>>, threshold: usize) -> Vec<Vec<Coord>> { let mut result = Vec::new(); for (row_idx, row) in matrix.iter().enumerate() { let mut coords = Vec::new(); for (col_idx, &val) in row.iter().enumerate() { if val as usize <= threshold { coords.push(Coord(row_idx, col_idx)); } } result.push(coords); } result }
- JS端调用示例:
import { find } from './your_wasm_module'; const matrix = [[1, 5, 3], [2, 4, 6]]; const threshold = 3; const result = find(matrix, threshold); // result 为 [[[0,0], [0,2]], [[1,0]]]
内容的提问来源于stack exchange,提问作者Roman Mahotskyi
相关产品推荐
相关产品推荐

