newechoes/src/content/理解计算机/rust/用rust实现第一个wasm.md

203 lines
4.3 KiB
Markdown
Raw Normal View History

---
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;
```