WebAssembly 編程入門,基於 Rust

這是我龍年的第一篇文章。首先,祝各位朋友龍年大吉!

我在 “WebAssembly 101” 一文中簡單介紹了 WebAssembly 語言的背景和基礎知識。我們說通常不會直接編寫 WebAssembly 代碼,而是由其它語言編譯而來。例如,一個簡單的求兩個數之和的 WebAssembly 代碼可能如下:

(module
    (func (export "add") (param i32 i32) (result i32)
        local.get 0
        local.get 1
        i32.add
    )
)

由於語法表達力的不足(只提供了非常精簡的指令),直接寫的話比較繁瑣。因此,最好使用表達力強的高級語言進行編碼,而後由編譯器生成 WebAssembly 代碼。可供選擇的編程語言有 C/C++、Rust、Go 等。在這衆多語言中,Rust 對 WebAssembly 的全方位支持可能是最好的。Rust 語言是一門較新的編程語言,近年來一直倍受開發者喜愛。我之前寫過一篇文章介紹了 Rust 語言:紅紅火火的 Rust 語言啊。下面,我們結合 Rust 來編寫 WebAssembly 並在網頁中查看效果。

對於上面兩數求合的函數,在 Rust 中的代碼實現如下:

#[wasm_bindgen]
pub fn add(x: f64, y: f64) -> f64 {
    x + y
}

相比於 WebAssembly,這裏的代碼更簡潔,也很容易讀懂代碼的意圖。有一處特殊的地方是:#[wasm_bindgen]。這是 Rust 宏命令語法,它由 “wasm-bindgen” 代碼包提供。它的意思是告訴編譯器:如果需要的話,請幫我生成一些輔助代碼,使得這個 Rust 語言中的函數可以在 WebAssembly 和 JavaScript 中使用。

爲了使用 #[wasm_bindgen],我們需要先安裝它。按如下修改 Rust 工程中的 Cargo.toml 文件:

[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"

編譯 WebAssembly

我們使用 wasm-pack 工具來將 Rust 代碼編譯成 WebAssembly 代碼,並同時生成 ESM 模塊代碼來方便在 JavaScript 中使用。在項目根目錄運行:

wasm-pack build

會生成如下代碼:

Rust 生成的 WebAssembly 被打包成了一個 npm 包,名爲 “wasm-greet”。這個包對外導出瞭如下函數:

/**
* @param {number} x
* @param {number} y
* @returns {number}
*/
export function add(x: number, y: number): number;

此處的 add 函數是在 WebAssembly 中定義並導出的。在 JavaScript 中,可以用如下方式使用在 WebAssembly 中定義的 add 函數:

import { add } from 'wasm-greet';
alert(add(1,2));

效果如下:

總結

如果從純代碼的角度看整個編程體驗,我們最初用 Rust 語言定義一個函數:

#[wasm_bindgen]
pub fn add(x: f64, y: f64) -> f64 {
    x + y
}

然後,在 JavaScript 代碼中用 ESM 的導入語句來導入這個函數:

import { add } from 'wasm-greet';

最後,就可以像使用普通 JavaScript 函數那樣來使用 add 函數。

接下來

我們用只接收數值類型和返回數值類型的 add 函數舉例是有意爲之。因爲在 WebAssembly 的底層(WASM 1.0 標準中),它只能直接處理 i32 ∣ i64 ∣ f32 ∣ f64 類型的值。那麼,如何定義一個接受字符串類型的函數呢?或者如何定義一個接受 JavaScript 回調函數的函數呢?我們需要一些變通方法,用數值來間接表示複雜對象類型。例如,使用一個字符起始指針、一個字符串長度變量,再結合 WebAssembly 的線性內存 Memory 特性來間接傳遞字符串。這些更加複雜的場景才更是 wasm-bindgen + wasm-pack 的用武之地,它會幫我們生成這些輔助代碼,而我們定義的函數只要聲明接收字符串參數即可:

pub fn greet(name: &str) {}

讓我們以後再聊這一部分。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HFiWF--h6OGCs3_F0M1Ezg