這是 wasm-pack未發布文件,已發布的文件可在 Rust 和 WebAssembly 主要文件網站 上找到。這裡記錄的功能可能在 wasm-pack 的發行版本中不可用。

src/lib.rs

lib.rs 是範本的主要原始碼檔案。名稱 lib.rs 通常意味著這個 Rust 專案將被編譯為函式庫。

它包含三個關鍵部分

  1. #[wasm_bindgen] 函式
  2. Crate 匯入
  3. wee_alloc 可選依賴項

我們將從 lib.rs 最重要的部分開始 - 兩個 #[wasm_bindgen] 函式(您可以在檔案底部找到它們)。在許多情況下,這是您唯一需要修改的 lib.rs 部分。

1. 使用 wasm_bindgen

為了更方便地從 wasm-bindgen crate 公開功能,我們可以使用 use 關鍵字。use 允許我們方便地引用 crate 或模組的部分內容。您可以在本書的這一章中了解更多關於 Rust 如何讓您編寫模組化程式碼的資訊。

#![allow(unused)]
fn main() {
use wasm_bindgen::prelude::*;
}

許多 crate 都包含一個 prelude,一個方便一次匯入所有內容的清單。這允許方便地訪問模組的常用功能,而無需冗長的前綴。例如,在這個檔案中,我們可以使用 #[wasm_bindgen] 僅僅是因為它是由 prelude 引入範圍的。

這個 use 結尾的星號表示 wasm_bindgen::prelude 模組(即 wasm_bindgen crate 內部的 prelude 模組)內的所有內容都可以在沒有 wasm_bindgen::prelude 前綴的情況下被引用。

例如,#[wasm_bindgen] 也可以寫成 #[wasm_bindgen::prelude::wasm_bindgen],儘管不建議這樣做。

1. #[wasm_bindgen] 函式

#[wasm_bindgen] 屬性表示它下面的函式在 JavaScript 和 Rust 中都可以訪問。

#![allow(unused)]
fn main() {
#[wasm_bindgen]
extern {
    fn alert(s: &str);
}
}

extern 區塊將外部 JavaScript 函式 alert 匯入到 Rust 中。這個聲明是從 Rust 中呼叫 alert 所必需的。通過以這種方式聲明它,wasm-bindgen 將為 alert 建立 JavaScript 存根,允許我們在 Rust 和 JavaScript 之間來回傳遞字串。

我們可以看到 alert 函式需要一個類型為 &str 的單一參數 s,即一個字串。在 Rust 中,任何字串字面量,例如 "Hello, test-wasm!" 都是 &str 類型的。所以,可以通過編寫 alert("Hello, test-wasm!"); 來呼叫 alert

我們知道要以這種方式聲明 alert,因為這是我們在 JavaScript 中呼叫 alert 的方式 - 通過傳遞一個字串參數給它。

#![allow(unused)]
fn main() {
#[wasm_bindgen]
pub fn greet() {
    alert("Hello, test-wasm!");
}
}

如果我們在沒有 #[wasm_bindgen] 屬性的情況下編寫 greet 函式,那麼 greet 將無法在 JavaScript 中輕鬆訪問。此外,我們將無法在本機轉換 JavaScript 和 Rust 之間的某些類型,例如 &str。所以,#[wasm_bindgen] 屬性和之前的 alert 匯入都允許從 JavaScript 中呼叫 greet

這就是您與 JavaScript 互動所需知道的所有內容,至少是開始!您可以通過閱讀 wasm-bindgen 文件了解更多資訊!

如果您對其餘部分感到好奇,請繼續閱讀。

2. Crate 組織

#![allow(unused)]
fn main() {
mod utils;
}

此語句聲明了一個名為 utils 的新模組,該模組由 utils.rs 的內容定義。等效地,我們可以將 utils.rs 的內容放在 utils 聲明中,將該行替換為

#![allow(unused)]
fn main() {
mod utils {
    // contents of utils.rs
}
}

無論哪種方式,utils.rs 的內容都定義了一個公共函式 set_panic_hook。因為我們將其放在 utils 模組中,所以我們將能夠通過編寫 utils::set_panic_hook() 直接呼叫該函式。我們將在 src/utils.rs 中討論如何以及為什麼要使用這個函式。

#![allow(unused)]
fn main() {
    // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
    // allocator.
    if #[cfg(feature = "wee_alloc")] {
        #[global_allocator]	static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
}

在編譯時,這將測試是否為此編譯啟用了 wee_alloc 功能。如果啟用了,我們將配置一個全域分配器(根據 wee_alloc 的文件),否則它將編譯為空。

正如我們之前看到的,[features] 中的 default 向量僅包含 "console_error_panic_hook",而不包含 "wee_alloc"。所以,在這種情況下,這個區塊將被替換為沒有任何程式碼,因此將使用預設的記憶體分配器而不是 wee_alloc