Chuyển đến nội dung chính

第 17 課:WebAssembly 與 Rust

wasm-pack、wasm-bindgen。 Rust → WASM 編譯。 JavaScript 互通、web-sys、js-sys。效能關鍵的瀏覽器程式碼。 Leptos/Yew 前端框架。

💻 程式設計 — 第 17 課 第 17 課:WebAssembly 與 Rust

Rust:從基礎到高級

第 5 部分:WebAssembly 和系統

亞洲開發網

1.WASM設定

# Cài tools
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
# Cargo.toml
[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["console", "Document", "Element", "HtmlElement"] }
js-sys = "0.3"
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => {
            let mut a: u64 = 0;
            let mut b: u64 = 1;
            for _ in 2..=n {
                let temp = a + b;
                a = b;
                b = temp;
            }
            b
        }
    }
}

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}
# Build
wasm-pack build --target web

2. JavaScript 互通

use wasm_bindgen::prelude::*;

// Import JS function
#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);

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

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

// Export struct to JS
#[wasm_bindgen]
pub struct ImageProcessor {
    width: u32,
    height: u32,
    pixels: Vec<u8>,
}

#[wasm_bindgen]
impl ImageProcessor {
    #[wasm_bindgen(constructor)]
    pub fn new(width: u32, height: u32) -> Self {
        Self {
            width, height,
            pixels: vec![0; (width * height * 4) as usize],
        }
    }

    pub fn grayscale(&mut self) {
        for chunk in self.pixels.chunks_mut(4) {
            let gray = (0.299 * chunk[0] as f64 + 0.587 * chunk[1] as f64 + 0.114 * chunk[2] as f64) as u8;
            chunk[0] = gray;
            chunk[1] = gray;
            chunk[2] = gray;
        }
    }

    pub fn pixels_ptr(&self) -> *const u8 {
        self.pixels.as_ptr()
    }
}

3. 使用 web-sys 操作 DOM

use web_sys::{Document, Element, window};

#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
    let window = window().unwrap();
    let document = window.document().unwrap();

    let div = document.create_element("div")?;
    div.set_inner_html("<h1>Hello from Rust WASM!</h1>");
    div.set_attribute("class", "rust-content")?;

    document.body().unwrap().append_child(&div)?;
    Ok(())
}

4.樂浦前端框架

use leptos::*;

#[component]
fn App() -> impl IntoView {
    let (count, set_count) = create_signal(0);

    view! {
        <div class="app">
            <h1>"Counter: " {count}</h1>
            <button on:click=move |_| set_count.update(|n| *n += 1)>
                "Increment"
            </button>
        </div>
    }
}

fn main() {
    leptos::mount_to_body(|| view! { <App/> });
}

下一篇: FFI 和不安全 Rust。