Rust 入门系列(第 5 篇,共 5 篇 - 完结篇) 前置阅读:第 4 篇 - 实战 CLI 工具 阅读时间:25 分钟
引言
WebAssembly(WASM) 是一种可以在浏览器中运行的二进制格式,性能接近原生代码。Rust 是编译到 WASM 最成熟的语言之一。
这篇文章会教你:
- ✅ 什么是 WebAssembly
- ✅ 为什么 Rust + WASM 是最佳组合
- ✅ 如何用 wasm-pack 构建 WASM 项目
- ✅ 实战:构建一个图像处理模块
一、WebAssembly 简介
1.1 什么是 WebAssembly?
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 官方文档:
- 无 GC:无垃圾回收,性能可预测
- 小体积:编译出的 WASM 模块很小
- 工具链成熟:wasm-pack、wasm-bindgen 等工具完善
- 类型安全:编译时检查,减少运行时错误
真实案例:
- Figma:渲染引擎
- Photoshop Web:图像处理
- Google Earth:3D 渲染
二、环境搭建
2.1 安装 wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh验证安装:
wasm-pack --version2.2 创建项目
cargo new --lib hello_wasm
cd hello_wasm2.3 配置 Cargo.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 代码
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}3.2 编译
wasm-pack build --target web输出:
pkg/
├── hello_wasm_bg.wasm # WASM 二进制文件
├── hello_wasm.js # JavaScript 绑定
├── hello_wasm.d.ts # TypeScript 类型定义
└── package.json3.3 在浏览器中使用
创建 index.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>启动本地服务器:
# Python
python3 -m http.server 8000
# Node.js
npx serve访问 http://localhost:8000,看到 “Hello, World!”。
四、实战:图像滤镜
4.1 项目目标
用 Rust 实现图像灰度化处理,性能远超 JavaScript。
4.2 添加依赖
[dependencies]
wasm-bindgen = "0.2"
image = "0.24"4.3 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 调用
<!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 版本
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
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 传递复杂数据
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)
}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
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 减小体积
# 优化编译
wasm-pack build --release
# 使用 wasm-opt
wasm-opt -Oz -o output.wasm input.wasm7.2 延迟加载
// 按需加载
button.addEventListener('click', async () => {
const wasm = await import('./pkg/heavy_module.js');
await wasm.default();
wasm.heavy_computation();
});7.3 Worker 中运行
// 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 推荐资源
书籍:
视频:
社区:
十一、结语
Rust 的学习曲线确实陡峭,但一旦掌握,你会发现它的设计哲学非常优雅:
- ✅ 安全:编译时保证内存安全
- ✅ 快速:零成本抽象,性能媲美 C/C++
- ✅ 并发:无畏并发,编译时检查数据竞争
- ✅ 现代化:优秀的工具链和生态
无论是系统编程、Web 开发、WebAssembly 还是区块链,Rust 都是一个值得投资的语言。
希望这个系列对你有帮助。Happy coding! 🦀
参考资料
- Rust and WebAssembly Book
- MDN: Compiling Rust to WebAssembly
- Rust WebAssembly Official Site
- Getting Started with WebAssembly and Rust - LogRocket
- The Minimal Rust-Wasm Setup
系列导航
系列完结!感谢阅读! 🎉