Skip to content

Rust WebAssembly

WebAssembly(Wasm)是一种可移植的二进制格式,允许在浏览器中运行高性能代码。Rust 提供了强大的 WebAssembly 支持。本章节将介绍 Rust 与 WebAssembly 的集成。

环境设置

安装 wasm-pack

wasm-pack 是 Rust WebAssembly 项目的构建工具:

bash
cargo install wasm-pack

安装 wasm-bindgen-cli

wasm-bindgen-cli 用于生成 Rust 和 JavaScript 之间的绑定:

bash
cargo install wasm-bindgen-cli

创建 WebAssembly 项目

使用 wasm-pack 初始化项目

bash
wasm-pack new wasm-demo
cd wasm-demo

项目结构

wasm-demo/
├── Cargo.toml
├── src/
│   ├── lib.rs
│   └── utils.rs
└── README.md

编写 WebAssembly 代码

基本示例

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

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

编译项目

bash
wasm-pack build --target web

这将生成以下文件:

pkg/
├── wasm_demo_bg.wasm
├── wasm_demo.js
├── wasm_demo.d.ts
└── package.json

在网页中使用

创建 HTML 文件

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Rust WebAssembly Demo</title>
</head>
<body>
    <h1>Rust WebAssembly Demo</h1>
    <button id="greet">Greet</button>
    <button id="add">Add</button>
    <div id="result"></div>
    
    <script type="module">
        import init, { greet, add } from './pkg/wasm_demo.js';
        
        async function run() {
            await init();
            
            document.getElementById('greet').addEventListener('click', () => {
                greet('World');
            });
            
            document.getElementById('add').addEventListener('click', () => {
                const result = add(5, 3);
                document.getElementById('result').textContent = `5 + 3 = ${result}`;
            });
        }
        
        run();
    </script>
</body>
</html>

运行项目

使用本地服务器运行项目:

bash
python -m http.server

然后在浏览器中访问 http://localhost:8000

与 JavaScript 交互

从 Rust 调用 JavaScript

rust
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    // 调用 console.log
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
    
    // 调用 DOM API
    #[wasm_bindgen(js_namespace = document)]
    fn getElementById(id: &str) -> Option<Element>;
    
    #[wasm_bindgen]
    type Element;
    
    #[wasm_bindgen(method)]
    fn innerHTML(this: &Element) -> String;
    
    #[wasm_bindgen(method)]
    fn set_innerHTML(this: &Element, value: &str);
}

#[wasm_bindgen]
pub fn update_element(id: &str, content: &str) {
    if let Some(element) = getElementById(id) {
        element.set_innerHTML(content);
        log(&format!("Updated element {} with content: {}", id, content));
    }
}

从 JavaScript 调用 Rust

rust
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct Counter {
    count: i32,
}

#[wasm_bindgen]
impl Counter {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        Counter { count: 0 }
    }
    
    pub fn increment(&mut self) {
        self.count += 1;
    }
    
    pub fn decrement(&mut self) {
        self.count -= 1;
    }
    
    pub fn get_count(&self) -> i32 {
        self.count
    }
}

JavaScript 代码:

javascript
import init, { Counter } from './pkg/wasm_demo.js';

async function run() {
    await init();
    
    const counter = new Counter();
    console.log('Initial count:', counter.get_count()); // 0
    
    counter.increment();
    console.log('After increment:', counter.get_count()); // 1
    
    counter.decrement();
    console.log('After decrement:', counter.get_count()); // 0
}

run();

性能优化

使用 wee_alloc 减少 Wasm 体积

Cargo.toml 中添加:

toml
[dependencies]
wasm-bindgen = "0.2"
wee_alloc = "0.4"

[profile.release]
opt-level = "s"

lib.rs 中使用:

rust
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

开启优化

bash
wasm-pack build --target web --release

总结

  • WebAssembly:一种可移植的二进制格式
  • wasm-pack:Rust WebAssembly 项目的构建工具
  • wasm-bindgen:生成 Rust 和 JavaScript 之间的绑定
  • 从 Rust 调用 JavaScript:使用 extern "C"
  • 从 JavaScript 调用 Rust:使用 #[wasm_bindgen]
  • 性能优化:使用 wee_alloc 和开启优化

Rust 与 WebAssembly 的集成使得我们可以在浏览器中运行高性能的 Rust 代码,为 Web 应用带来更好的性能体验。通过本章节的学习,你应该已经掌握了 Rust 与 WebAssembly 集成的基本方法。