如何基于wasm-bindgen实现支持JS解构的Rust WASM构造函数
问题
我正在使用rust-wasm与wasm-bindgen为Rust库创建JavaScript包装器。当前定义的Rust构造函数如下:
#[wasm_bindgen(js_class = Dater)] impl DaterWrapper { #[wasm_bindgen(constructor)] pub fn new( dts: Option<String>, code: Option<String>, raw: Option<Vec<u8>>, qb64b: Option<Vec<u8>>, qb64: Option<String>, qb2: Option<Vec<u8>>, ) -> Result<DaterWrapper> { let dater = Dater::new( dts.as_deref(), code.as_deref(), raw.as_deref(), qb64b.as_deref(), qb64.as_deref(), qb2.as_deref(), ) .as_js()?; Ok(DaterWrapper(dater)) }
它生成的JavaScript构造函数为:
constructor(dts?: string, code?: string, raw?: Uint8Array, qb64b?: Uint8Array, qb64?: string, qb2?: Uint8Array);
该构造函数不支持JavaScript解构。我希望通过解构实现命名参数构造,例如new Dater({dts: now_datetime}),请问如何修改Rust构造函数以支持该调用方式?
解决方案
要实现JS的命名参数构造,得定义一个结构体来映射JS传入的配置对象,然后在构造函数中接收这个结构体作为参数。具体操作如下:
1. 定义配置结构体
先创建一个与JS配置对象对应的Rust结构体,用#[wasm_bindgen]标记,确保wasm-bindgen能生成对应的JS类型:
#[wasm_bindgen] pub struct DaterOptions { pub dts: Option<String>, pub code: Option<String>, pub raw: Option<Vec<u8>>, pub qb64b: Option<Vec<u8>>, pub qb64: Option<String>, pub qb2: Option<Vec<u8>>, }
结构体字段名要和你期望的JS对象属性名完全一致,且都设为Option类型以支持可选参数。
2. 修改构造函数参数
把原构造函数的多个参数替换成这个配置结构体:
#[wasm_bindgen(js_class = Dater)] impl DaterWrapper { #[wasm_bindgen(constructor)] pub fn new(options: DaterOptions) -> Result<DaterWrapper> { let dater = Dater::new( options.dts.as_deref(), options.code.as_deref(), options.raw.as_deref(), options.qb64b.as_deref(), options.qb64.as_deref(), options.qb2.as_deref(), ) .as_js()?; Ok(DaterWrapper(dater)) } }
3. (可选)支持无参数调用
如果需要允许new Dater()这种无参数调用,给构造函数的参数加上Option包裹,并为DaterOptions实现Default trait:
// 实现Default trait,生成默认空配置 impl Default for DaterOptions { fn default() -> Self { DaterOptions { dts: None, code: None, raw: None, qb64b: None, qb64: None, qb2: None, } } } // 修改构造函数 #[wasm_bindgen(js_class = Dater)] impl DaterWrapper { #[wasm_bindgen(constructor)] pub fn new(options: Option<DaterOptions>) -> Result<DaterWrapper> { let opts = options.unwrap_or_default(); let dater = Dater::new( opts.dts.as_deref(), opts.code.as_deref(), opts.raw.as_deref(), opts.qb64b.as_deref(), opts.qb64.as_deref(), opts.qb2.as_deref(), ) .as_js()?; Ok(DaterWrapper(dater)) } }
最终效果
修改后生成的JS构造函数会变为:
constructor(options?: DaterOptions);
现在你可以用命名参数的方式调用:
// 仅传入dts参数 const dater1 = new Dater({ dts: now_datetime }); // 传入多个参数 const dater2 = new Dater({ dts: "2024-05-20", code: "CN", raw: new Uint8Array([1,2,3]) }); // 无参数调用(如果做了可选处理) const dater3 = new Dater();
内容的提问来源于stack exchange,提问作者daidoji70
相关产品推荐
相关产品推荐

