Работа с WebAssembly и Rust: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в WebAssembly и Rust

WebAssembly (WASM) — это низкоуровневый бинарный формат инструкций, который позволяет запускать высокопроизводительный код в браузере почти с нативной скоростью. Rust, с его системой владения и отсутствием сборщика мусора, является идеальным языком для компиляции в WebAssembly. В этой статье мы пройдем путь от установки инструментов до создания полноценного WASM-модуля на Rust.

Почему именно Rust? Он предоставляет безопасную работу с памятью, минимальный размер бинарника и отличную производительность. В сочетании с WebAssembly вы получаете возможность писать сложные алгоритмы, игры, графические редакторы и даже полноценные приложения, работающие в браузере.

Установка инструментов и подготовка окружения

Для начала работы вам понадобятся:

  • Rust (установленный через rustup)
  • Целевая платформа wasm32-unknown-unknown
  • Инструмент wasm-pack (сборка и публикация WASM)
  • Базовый HTTP-сервер (например, python3 -m http.server)

Установка целевой платформы и wasm-pack:

# Установка целевой платформы для WebAssembly
rustup target add wasm32-unknown-unknown

# Установка wasm-pack
cargo install wasm-pack

Теперь создадим новый проект:

cargo new --lib wasm-rust-demo
cd wasm-rust-demo

Откройте Cargo.toml и добавьте зависимость:

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

[dependencies]
wasm-bindgen = "0.2"

Флаг cdylib указывает, что мы создаем динамическую библиотеку, совместимую с WebAssembly.

Написание первого WASM-модуля на Rust

Создадим простую функцию, которая будет доступна из JavaScript. Отредактируйте src/lib.rs:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Привет, {}! Добро пожаловать в мир WebAssembly!", name)
}

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

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

Атрибут #[wasm_bindgen] позволяет экспортировать функции в JavaScript. Обратите внимание: String автоматически конвертируется в JavaScript-строку.

Теперь соберем проект:

wasm-pack build --target web

После сборки в папке pkg появятся файлы:

  • wasm_rust_demo_bg.wasm — скомпилированный WASM-модуль
  • wasm_rust_demo.js — JavaScript-обертка для удобного импорта
  • wasm_rust_demo.d.ts — TypeScript-декларации

Интеграция с JavaScript и HTML

Создайте файл index.html в корне проекта:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rust + WebAssembly Demo</title>
</head>
<body>
    <h1>Rust + WebAssembly Пример</h1>
    
    <div>
        <h3>Функция greet</h3>
        <input type="text" id="nameInput" placeholder="Введите имя" value="Мир">
        <button id="greetBtn">Поприветствовать</button>
        <p id="greetOutput"></p>
    </div>

    <div>
        <h3>Числа Фибоначчи</h3>
        <input type="number" id="fibInput" value="10" min="0" max="40">
        <button id="fibBtn">Вычислить</button>
        <p id="fibOutput"></p>
    </div>

    <script type="module">
        import init, { greet, fibonacci, add } from './pkg/wasm_rust_demo.js';

        async function run() {
            await init();

            document.getElementById('greetBtn').addEventListener('click', () => {
                const name = document.getElementById('nameInput').value;
                const result = greet(name);
                document.getElementById('greetOutput').textContent = result;
            });

            document.getElementById('fibBtn').addEventListener('click', () => {
                const n = parseInt(document.getElementById('fibInput').value);
                const result = fibonacci(n);
                document.getElementById('fibOutput').textContent = 
                    `Fibonacci(${n}) = ${result}`;
            });

            // Демонстрация add
            console.log('2 + 3 =', add(2, 3));
        }

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

Запустите HTTP-сервер:

python3 -m http.server 8000

Откройте браузер по адресу http://localhost:8000. Вы увидите работающее приложение, где функции Rust вызываются из JavaScript.

Работа с памятью и сложными типами данных

Иногда нужно передавать более сложные структуры данных. wasm-bindgen поддерживает сериализацию через serde и работу с массивами.

Добавим в Cargo.toml:

[dependencies]
wasm-bindgen = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_wasm_bindgen = "0.6"

Теперь создадим структуру и функцию для работы с ней:

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

#[derive(Serialize, Deserialize)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

#[wasm_bindgen]
pub fn calculate_distance(p1: JsValue, p2: JsValue) -> JsValue {
    let point1: Point = serde_wasm_bindgen::from_value(p1).unwrap();
    let point2: Point = serde_wasm                

Блоги

Рекомендаций по книгам