203 lines
4.3 KiB
Markdown
203 lines
4.3 KiB
Markdown
---
|
||
title: "用Rust实现WebAssembly模块"
|
||
date: 2024-10-19T15:09:25+08:00
|
||
tags: ["rust", "webassembly"]
|
||
---
|
||
|
||
## 准备工作
|
||
|
||
### 1. 安装Rust
|
||
|
||
确保已安装Rust环境:
|
||
|
||
```bash
|
||
rustc --version
|
||
```
|
||
|
||
如果未安装,可以访问[Rust官网](https://www.rust-lang.org/tools/install)按照指引进行安装。
|
||
|
||
### 2. 安装wasm-pack
|
||
|
||
wasm-pack是将Rust代码编译为WebAssembly的工具:
|
||
|
||
```bash
|
||
cargo install wasm-pack
|
||
```
|
||
|
||
## 创建和构建WebAssembly模块
|
||
|
||
### 1. 创建Rust库项目
|
||
|
||
```bash
|
||
cargo new --lib my_wasm
|
||
cd my_wasm
|
||
```
|
||
|
||
### 2. 配置Cargo.toml
|
||
|
||
修改`Cargo.toml`文件,添加必要的依赖和配置:
|
||
|
||
```toml
|
||
[package]
|
||
name = "my_wasm"
|
||
version = "0.1.0"
|
||
edition = "2021"
|
||
|
||
[lib]
|
||
crate-type = ["cdylib", "rlib"]
|
||
|
||
[dependencies]
|
||
wasm-bindgen = "0.2.95"
|
||
# 以下是可选依赖,根据项目需求添加
|
||
js-sys = "0.3.64"
|
||
web-sys = { version = "0.3.64", features = ["console"] }
|
||
```
|
||
|
||
### 3. 编写Rust代码
|
||
|
||
在`src/lib.rs`中编写导出到WebAssembly的代码:
|
||
|
||
```rust
|
||
use wasm_bindgen::prelude::*;
|
||
|
||
// 导入JavaScript函数
|
||
#[wasm_bindgen]
|
||
extern "C" {
|
||
// 导入JavaScript的console.log函数
|
||
#[wasm_bindgen(js_namespace = console)]
|
||
fn log(s: &str);
|
||
}
|
||
|
||
// 简单的结构体示例
|
||
#[wasm_bindgen]
|
||
pub struct Processor {
|
||
value: i32,
|
||
}
|
||
|
||
#[wasm_bindgen]
|
||
impl Processor {
|
||
// 构造函数
|
||
#[wasm_bindgen(constructor)]
|
||
pub fn new() -> Self {
|
||
Processor { value: 0 }
|
||
}
|
||
|
||
// 简单的方法
|
||
pub fn increment(&mut self, amount: i32) -> i32 {
|
||
self.value += amount;
|
||
self.value
|
||
}
|
||
|
||
// 返回处理结果的方法
|
||
pub fn process_data(&self, input: &str) -> String {
|
||
log(&format!("Processing data: {}", input));
|
||
format!("Processed: {} (value={})", input, self.value)
|
||
}
|
||
}
|
||
|
||
// 单独的函数也可以导出
|
||
#[wasm_bindgen]
|
||
pub fn add(a: i32, b: i32) -> i32 {
|
||
a + b
|
||
}
|
||
```
|
||
|
||
### 4. 构建WebAssembly模块
|
||
|
||
使用wasm-pack构建WebAssembly模块,指定target为web:
|
||
|
||
```bash
|
||
wasm-pack build --target web
|
||
```
|
||
|
||
这将在`pkg/`目录下生成以下文件:
|
||
|
||
- `my_wasm.js` - JavaScript包装代码
|
||
- `my_wasm_bg.wasm` - WebAssembly二进制文件
|
||
- `my_wasm_bg.js` - JavaScript胶水代码
|
||
- 其他类型定义和元数据文件
|
||
|
||
## 在Web应用中使用WebAssembly模块
|
||
|
||
在React组件中使用WebAssembly模块的示例:
|
||
|
||
```tsx
|
||
import React, { useEffect, useState } from 'react';
|
||
|
||
interface MyWasmModule {
|
||
Processor: new () => {
|
||
increment: (amount: number) => number;
|
||
process_data: (input: string) => string;
|
||
};
|
||
add: (a: number, b: number) => number;
|
||
default?: () => Promise<any>;
|
||
}
|
||
|
||
const WasmExample: React.FC = () => {
|
||
const [result, setResult] = useState<string>('');
|
||
const [wasmModule, setWasmModule] = useState<MyWasmModule | null>(null);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
const loadWasm = async () => {
|
||
try {
|
||
// 动态导入WASM模块
|
||
const wasm = await import('@/assets/wasm/my_wasm/my_wasm.js');
|
||
|
||
// 初始化WASM模块
|
||
if (typeof wasm.default === 'function') {
|
||
await wasm.default();
|
||
}
|
||
|
||
setWasmModule(wasm as unknown as MyWasmModule);
|
||
} catch (err) {
|
||
console.error('加载WASM模块失败:', err);
|
||
setError(`WASM模块加载失败: ${err instanceof Error ? err.message : String(err)}`);
|
||
}
|
||
};
|
||
|
||
loadWasm();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (!wasmModule) return;
|
||
|
||
try {
|
||
// 使用WASM模块中的函数
|
||
const sum = wasmModule.add(10, 20);
|
||
console.log(`10 + 20 = ${sum}`);
|
||
|
||
// 使用WASM模块中的类
|
||
const processor = new wasmModule.Processor();
|
||
processor.increment(15);
|
||
const processResult = processor.process_data("React与WASM");
|
||
|
||
setResult(processResult);
|
||
} catch (err) {
|
||
console.error('使用WASM模块失败:', err);
|
||
setError(`WASM操作失败: ${err instanceof Error ? err.message : String(err)}`);
|
||
}
|
||
}, [wasmModule]);
|
||
|
||
if (error) {
|
||
return <div className="error-message">{error}</div>;
|
||
}
|
||
|
||
return (
|
||
<div className="wasm-example">
|
||
<h2>WebAssembly示例</h2>
|
||
{!wasmModule ? (
|
||
<p>正在加载WASM模块...</p>
|
||
) : (
|
||
<div>
|
||
<p>WASM处理结果:</p>
|
||
<pre>{result}</pre>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default WasmExample;
|
||
```
|