---
title: Rust 入门（五）：Rust + WebAssembly 实战
slug: rust-intro-wasm
date: 2026-01-11
author: Frankie 徐
category: fullstack
tags: ['rust', 'webassembly', 'wasm', 'web', 'performance']
description: Rust 入门系列最后一篇：学习如何用 Rust 编写 WebAssembly 模块，在浏览器中运行高性能代码
permalink: https://www.210k.cc/rust-intro-wasm
---

> **Rust 入门系列**（第 5 篇，共 5 篇 - 完结篇）
> **前置阅读**：[第 4 篇 - 实战 CLI 工具](/rust-intro-cli-project)
> **阅读时间**：25 分钟

---

## 引言

**WebAssembly（WASM）** 是一种可以在浏览器中运行的二进制格式，性能接近原生代码。Rust 是编译到 WASM 最成熟的语言之一。

这篇文章会教你：
- ✅ 什么是 WebAssembly
- ✅ 为什么 Rust + WASM 是最佳组合
- ✅ 如何用 wasm-pack 构建 WASM 项目
- ✅ 实战：构建一个图像处理模块

---

## 一、WebAssembly 简介

### 1.1 什么是 WebAssembly？

[MDN 定义](https://developer.mozilla.org/en-US/docs/WebAssembly/Guides/Rust_to_Wasm)：

> WebAssembly is a type of code that can be run in modern web browsers — it is a low-level assembly-like language with a compact binary format.

**关键特性**：
- 🚀 **高性能**：接近原生速度
- 🌐 **跨平台**：浏览器、Node.js、服务端
- 🔒 **安全**：沙箱环境运行
- 📦 **体积小**：二进制格式，压缩后更小

### 1.2 为什么用 Rust 编译 WASM？

根据 [Rust 官方文档](https://rust-lang.org/what/wasm/)：

1. **无 GC**：无垃圾回收，性能可预测
2. **小体积**：编译出的 WASM 模块很小
3. **工具链成熟**：wasm-pack、wasm-bindgen 等工具完善
4. **类型安全**：编译时检查，减少运行时错误

**真实案例**：
- Figma：渲染引擎
- Photoshop Web：图像处理
- Google Earth：3D 渲染

---

## 二、环境搭建

### 2.1 安装 wasm-pack

[官方安装指南](https://rustwasm.github.io/book/)：

```bash
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
```

**验证安装**：
```bash
wasm-pack --version
```

### 2.2 创建项目

```bash
cargo new --lib hello_wasm
cd hello_wasm
```

### 2.3 配置 Cargo.toml

```toml
[package]
name = "hello_wasm"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
```

---

## 三、Hello World

### 3.1 编写 Rust 代码

```rust
// src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}
```

### 3.2 编译

```bash
wasm-pack build --target web
```

**输出**：
```
pkg/
├── hello_wasm_bg.wasm         # WASM 二进制文件
├── hello_wasm.js              # JavaScript 绑定
├── hello_wasm.d.ts            # TypeScript 类型定义
└── package.json
```

### 3.3 在浏览器中使用

创建 `index.html`：

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello WASM</title>
</head>
<body>
    <h1>Hello WebAssembly!</h1>
    <script type="module">
        import init, { greet } from './pkg/hello_wasm.js';

        async function run() {
            await init();
            const result = greet('World');
            document.body.innerHTML += `<p>${result}</p>`;
        }

        run();
    </script>
</body>
</html>
```

**启动本地服务器**：
```bash
# Python
python3 -m http.server 8000

# Node.js
npx serve
```

访问 `http://localhost:8000`，看到 "Hello, World!"。

---

## 四、实战：图像滤镜

### 4.1 项目目标

用 Rust 实现图像灰度化处理，性能远超 JavaScript。

### 4.2 添加依赖

```toml
[dependencies]
wasm-bindgen = "0.2"
image = "0.24"
```

### 4.3 Rust 代码

```rust
use wasm_bindgen::prelude::*;
use image::{ImageBuffer, Rgba};

#[wasm_bindgen]
pub struct Image {
    width: u32,
    height: u32,
    data: Vec<u8>,
}

#[wasm_bindgen]
impl Image {
    #[wasm_bindgen(constructor)]
    pub fn new(width: u32, height: u32, data: Vec<u8>) -> Image {
        Image { width, height, data }
    }

    pub fn grayscale(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(self.data.len());

        for chunk in self.data.chunks(4) {
            let r = chunk[0] as f32;
            let g = chunk[1] as f32;
            let b = chunk[2] as f32;
            let a = chunk[3];

            // 灰度公式
            let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;

            result.push(gray);
            result.push(gray);
            result.push(gray);
            result.push(a);
        }

        result
    }
}
```

### 4.4 JavaScript 调用

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Image Filter</title>
</head>
<body>
    <h1>图像灰度化</h1>
    <input type="file" id="upload" accept="image/*">
    <br>
    <canvas id="original"></canvas>
    <canvas id="filtered"></canvas>

    <script type="module">
        import init, { Image } from './pkg/hello_wasm.js';

        await init();

        const upload = document.getElementById('upload');
        const originalCanvas = document.getElementById('original');
        const filteredCanvas = document.getElementById('filtered');

        upload.addEventListener('change', async (e) => {
            const file = e.target.files[0];
            const bitmap = await createImageBitmap(file);

            // 绘制原图
            originalCanvas.width = bitmap.width;
            originalCanvas.height = bitmap.height;
            const originalCtx = originalCanvas.getContext('2d');
            originalCtx.drawImage(bitmap, 0, 0);

            // 获取像素数据
            const imageData = originalCtx.getImageData(0, 0, bitmap.width, bitmap.height);

            // Rust 处理
            const img = new Image(bitmap.width, bitmap.height, Array.from(imageData.data));
            const grayData = img.grayscale();

            // 绘制灰度图
            filteredCanvas.width = bitmap.width;
            filteredCanvas.height = bitmap.height;
            const filteredCtx = filteredCanvas.getContext('2d');
            const newImageData = new ImageData(
                new Uint8ClampedArray(grayData),
                bitmap.width,
                bitmap.height
            );
            filteredCtx.putImageData(newImageData, 0, 0);
        });
    </script>
</body>
</html>
```

---

## 五、性能对比

### 5.1 JavaScript 版本

```javascript
function grayscaleJS(imageData) {
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
        data[i] = gray;
        data[i + 1] = gray;
        data[i + 2] = gray;
    }
    return imageData;
}
```

### 5.2 性能测试

```javascript
// JavaScript
console.time('JS');
grayscaleJS(imageData);
console.timeEnd('JS');

// Rust WASM
console.time('WASM');
const grayData = img.grayscale();
console.timeEnd('WASM');
```

**结果（1920x1080 图像）**：
- JavaScript：~50ms
- Rust WASM：~10ms
- **性能提升：5x**

---

## 六、与 JavaScript 互操作

### 6.1 传递复杂数据

```rust
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct User {
    name: String,
    age: u32,
}

#[wasm_bindgen]
pub fn process_user(json: &str) -> String {
    let user: User = serde_json::from_str(json).unwrap();
    format!("{} is {} years old", user.name, user.age)
}
```

```javascript
import { process_user } from './pkg/hello_wasm.js';

const user = { name: 'Alice', age: 30 };
const result = process_user(JSON.stringify(user));
console.log(result); // "Alice is 30 years old"
```

### 6.2 从 Rust 调用 JavaScript

```rust
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);

    #[wasm_bindgen(js_namespace = Math)]
    fn random() -> f64;
}

#[wasm_bindgen]
pub fn generate_random() -> i32 {
    let r = random();
    log(&format!("Random: {}", r));
    (r * 100.0) as i32
}
```

---

## 七、优化技巧

### 7.1 减小体积

```bash
# 优化编译
wasm-pack build --release

# 使用 wasm-opt
wasm-opt -Oz -o output.wasm input.wasm
```

### 7.2 延迟加载

```javascript
// 按需加载
button.addEventListener('click', async () => {
    const wasm = await import('./pkg/heavy_module.js');
    await wasm.default();
    wasm.heavy_computation();
});
```

### 7.3 Worker 中运行

```javascript
// worker.js
importScripts('./pkg/hello_wasm.js');

self.addEventListener('message', async (e) => {
    const result = process_data(e.data);
    self.postMessage(result);
});
```

---

## 八、实际应用场景

### 8.1 适合 WASM 的场景

✅ **CPU 密集型**：
- 图像/视频处理
- 3D 渲染
- 加密/解密
- 压缩/解压缩
- 科学计算

✅ **需要性能的库**：
- 游戏引擎
- PDF 渲染器
- 音频处理

### 8.2 不适合的场景

❌ **DOM 操作频繁**：JavaScript 更方便
❌ **简单逻辑**：WASM 的引入成本不值得
❌ **需要大量 JS API**：互操作开销大

---

## 九、工具链

### 9.1 wasm-pack

**主要功能**：
- 编译 Rust 到 WASM
- 生成 JavaScript 绑定
- 生成 TypeScript 类型定义
- 发布到 npm

### 9.2 wasm-bindgen

**功能**：
- Rust 和 JavaScript 互操作
- 自动生成绑定代码
- 类型转换

### 9.3 调试工具

**Chrome DevTools**：
- 支持 WASM 调试
- 可以查看 WASM 模块
- Source Map 支持

---

## 十、系列总结

### 10.1 我们学到了什么？

这个系列覆盖了 Rust 的核心内容：

**第 1 篇**：了解 Rust 的应用场景和真实案例
**第 2 篇**：掌握基础语法（变量、类型、函数、控制流、Struct/Enum）
**第 3 篇**：理解所有权、借用、生命周期（Rust 的灵魂）
**第 4 篇**：实战 CLI 工具（文件 I/O、错误处理、测试）
**第 5 篇**：Rust + WebAssembly（高性能 Web 应用）

### 10.2 下一步学习方向

**深入 Rust**：
- 异步编程（async/await、Tokio）
- 宏（macro_rules!、过程宏）
- 高级 trait（关联类型、泛型）

**Web 开发**：
- Actix-web / Axum（后端框架）
- Yew / Leptos（前端框架）
- Diesel / SQLx（数据库）

**系统编程**：
- 嵌入式开发
- 操作系统开发
- 网络编程

**区块链**：
- Solana 开发
- Substrate 框架

### 10.3 推荐资源

**书籍**：
- [The Rust Programming Language](https://doc.rust-lang.org/book/)
- [Rust by Example](https://doc.rust-lang.org/rust-by-example/)
- [The Rustonomicon](https://doc.rust-lang.org/nomicon/)（高级）

**视频**：
- [Let's Get Rusty](https://www.youtube.com/@letsgetrusty)
- [Jon Gjengset](https://www.youtube.com/@jonhoo)

**社区**：
- [r/rust](https://reddit.com/r/rust)
- [Rust Users Forum](https://users.rust-lang.org/)
- [This Week in Rust](https://this-week-in-rust.org/)

---

## 十一、结语

Rust 的学习曲线确实陡峭，但一旦掌握，你会发现它的设计哲学非常优雅：

- ✅ **安全**：编译时保证内存安全
- ✅ **快速**：零成本抽象，性能媲美 C/C++
- ✅ **并发**：无畏并发，编译时检查数据竞争
- ✅ **现代化**：优秀的工具链和生态

无论是系统编程、Web 开发、WebAssembly 还是区块链，Rust 都是一个值得投资的语言。

希望这个系列对你有帮助。Happy coding! 🦀

---

## 参考资料

- [Rust and WebAssembly Book](https://rustwasm.github.io/book/)
- [MDN: Compiling Rust to WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly/Guides/Rust_to_Wasm)
- [Rust WebAssembly Official Site](https://rust-lang.org/what/wasm/)
- [Getting Started with WebAssembly and Rust - LogRocket](https://blog.logrocket.com/getting-started-with-webassembly-and-rust/)
- [The Minimal Rust-Wasm Setup](https://dzfrias.dev/blog/rust-wasm-minimal-setup/)

---

## 系列导航

- **上一篇**：[Rust 入门（四）：实战项目 - 构建命令行工具](/rust-intro-cli-project)

**系列完结！感谢阅读！** 🎉