閱讀更多
引用
原文:JavaScript to Rust and Back Again: A wasm-bindgen Tale
鏈接:https://hacks.mozilla.org/2018/04/javascript-to-rust-and-back-again-a-wasm-bindgen-tale/
譯者:Tocy, 琪花億草, 雪落無痕xdj, 邊城

最近我們已經見識了WebAssembly如何快速編譯、加速JS庫以及生成更小的二進制格式。我們甚至為Rust和JavaScript社區以及其他Web編程語言之間的更好的互操作性制定了高級規劃。正如前面一篇文章中提到的,我想深入了解一個特定組件的細節,wasm-bindgen。

今天WebAssembly標準只定義了四種類型:兩種整數類型和兩種浮點類型。然而,大多數情況下,JS和Rust開發人員正在使用更豐富的類型! 例如,JS開發人員經常與互以添加或修改HTML節點相關的文檔交互,而Rust開發人員使用類似Result等類型進行錯誤處理,幾乎所有程序員都使用字符串。


被局限在僅使用由WebAssembly所提供的類型將會受到太多的限制,這就是wasm-bindgen出現的原因。


wasm-bindgen的目標是提供一個JS和Rust類型之間的橋接。它允許JS使用字符串調用Rust API,或Rust函數捕獲JS異常。wasm-bindgen抹平了WebAssembly和JavaScript之間的阻抗失配,確保JavaScript可以高效地調用WebAssembly函數,并且無需boilerplate,同時WebAssembly可以對JavaScript函數執行相同的操作。

wasm-bindgen項目在其README文件中有更多描述。要入門,讓我們深入到一個使用wasm-bindgen的例子中,然后探索它還有提供了什么。

1、Hello World!

學習新工具的最好也是最經典的方法之一就是探索下用它來輸出“Hello, World!”。在這里,我們將探索一個這樣的例子——在頁面里彈出“Hello World!”提醒框。

這里的目標很簡單,我們想要定義一個Rust的函數,給定一個名字,它會在頁面上創建一個對話框,上面寫著Hello,$name!在JavaScript中,我們可以將這個函數定義為:
export function greet(name) {
    alert(`Hello, ${name}!`);
}

不過在這個例子里要注意的是,我們將把它用Rust編寫。這里已經發生了很多我們必須要處理的事情:
  • JavaScript將會調用一個WebAssembly 模塊, 模塊名是 greetexport.
  • Rust函數將一個字符串作為輸入參數,也就是我們要打招呼的名字。
  • 在內部Rust會生成一個新的字符串,也就是傳入的名字。
  • 最后Rust會調用JavaScript的 alert函數,以剛創建的字符串作為參數。
啟動第一步,我們創建一個新的Rust工程:
$ cargo new wasm-greet --lib

這將初始化一個新的wasm-greet文件夾,我們的工作都在這里面完成。接下來我們要使用如下信息修改我們的Cargo.toml(在Rust里相當于package.json):
[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

我們先忽略[lib]節的內容,接下來的部分聲明了對wasm-bindgen的依賴。這里的依賴包含了我們使用wasm-bindgen需要的所有的支持包。

接下來,是時候編寫一些代碼了!我們使用下列內容替換了自動創建的src/lib.rs:
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

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

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

如果你不熟悉Rust,這可能看起來有點啰嗦,但不要害怕!隨著時間的推移,wasm-bindgen項目不斷改進,而且可以肯定的是,所有這些并不總是必要的。

要注意的最重要的一點是#[wasm_bindgen]屬性,這是一個在Rust代碼中的注釋,這里的意思是“請在必要時用wrapper處理這個”。我們對alert函數的導入和greet函數的導出都被標注為這個屬性。稍后,我們將看到在引擎蓋下發生了什么。

首先,我們從在瀏覽器中打開作為例子來切入正題!我們先編譯wasm代碼:
$ rustup target add wasm32-unknown-unknown --toolchain nightly # only needed once
$ cargo +nightly build --target wasm32-unknown-unknown

這段代碼會生成一個wasm文件,路徑為target/wasm32-unknown-unknown/debug/wasm_greet.wasm。如果我們使用工具如wasm2wat來看這個wasm文件里面的內容,可能會有點嚇人。

結果發現這個wasm文件實際上還不能直接被JS調用!為了能讓我們使用,我們需要執行一個或更多步驟:
$ cargo install wasm-bindgen-cli # only needed once
$ wasm-bindgen target/wasm32-unknown-unknown/debug/wasm_greet.wasm --out-dir .

很多不可思議的事情發生都發生在這個步驟中:wasm-bindgen CLI工具對輸入的wasm文件做后期處理,使它變的“suitable”可用。

我們待會再來看“suitable”的意思,現在我們可以肯定的說,如果我們引入剛創建的wasm_greet.js文件(wasm-bindgen工具創建的),我們已經獲取到了在Rust中定義的greet函數。

最終我們接下來要做的是使用bundler對其打包,然后創建一個HTML頁面運行我們的代碼。

在寫這篇文章的時候,只有Webpack’s 4.0 release對WebAssembly的使用有足夠的支持(盡管暫時已經有了 Chrome caveat)。

總有一天,更多的bundler也會接著支持WebAssmbly。在這我不再描述細節,但是你可以看一下在Github倉庫里的example配置。不過如果我們看內容,這個頁面中我們的JS在看起來是這樣的:
const rust = import("./wasm_greet");
rust.then(m => m.greet("World!"));

…就是這些了!現在打開我們的網頁就會顯示一個不錯的“Hello, World!”對話框,這就是Rust驅動的。

2、wasm-bindgen是如何工作的
唷,那是一個巨大的“Hello, World!”。讓我們深入了解一下更多的細節,以了解后臺發生了什么以及該工具是如何工作的。

wasm-bindgen最重要的方面之一就是它的集成基本上是建立在一個概念之上的,即一個wasm模塊僅是另一種ES模塊。例如,在上述中我們想要一個帶有如下簽名的ES模塊(在Typescript中):
export function greet(s: string);

WebAssembly無法在本地執行此操作(請記住,它目前只支持數字),所以我們依靠wasm-bindgen來填補空白。

在上述的最后一步中,當我們運行wasm-bindgen工具時,你會注意到wasm_greet.js文件與wasm_greet_bg.wasm文件一起出現。前者是我們想要的實際JS接口,執行任何必要的處理以調用Rust。* _bg.wasm文件包含實際的實現和我們所有的編譯后的代碼。

我們可以通過引入 ./wasm_greet 模塊得到 Rust 代碼愿意暴露出來的東西。我們已經看到了是如何集成的,可以繼續看看執行的結果如何。首先是我們的示例:
const rust = import("./wasm_greet");
rust.then(m => m.greet("World!"));

我們在這里以異步的方式導入接口,等待導入完成(下載和編譯 wasm)。然后調用模塊的 greet 函數。

注: 這里用到的異步加載目前需要 Webpack 來實現,但總會不需要的。而且,其它打包工具可能沒有此功能。

如果我們看看由 wasm-bindgen 工具為 wasm_greet.js 文件生成的內容,會看到像這樣的代碼:
import * as wasm from './wasm_greet_bg';

// ...

export function greet(arg0) {
    const [ptr0, len0] = passStringToWasm(arg0);
    try {
        const ret = wasm.greet(ptr0, len0);
        return ret;
    } finally {
        wasm.__wbindgen_free(ptr0, len0);
    }
}

export function __wbg_f_alert_alert_n(ptr0, len0) {
    // ...
}

注: 記住這是生成的,未經優化的代碼,它可能既不優雅也不簡潔!!在 Rust 中通過 LTO(Link Time Optimization,連接時優化)創建新的發行版,再通過 JS 打包工具流程(壓縮)之后,可能會精簡一些。

現在可以了解如何使用wasm-bindgen來生成greet函數。在底層它仍然調用wasm的greet函數,但是它是用一個指針和長度來調用的而不是用字符串。

了解passStringToWasm的更多細節可以訪問Lin Clark’s previous post。它包含了所有的模板,對我們來說這是除了wasm-bindgen工具以外還需要去寫的東西!然后我們接下來看__wbg_f_alert_alert_n函數。

進入更深一層,下一個我們感興趣的就是WebAssmbly中的greet函數。為了了解這個,我們先來看Rust編譯器能訪問到的代碼。注意像上面生成的這種JS wrapper,在這里你不用寫greet的導出符號,#[wasm_bindgen]屬性會生成一個shim,由它來為你翻譯,命名如下:
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

#[export_name = "greet"]
pub extern fn __wasm_bindgen_generated_greet(arg0_ptr: *mut u8, arg0_len: usize) {
    let arg0 = unsafe { ::std::slice::from_raw_parts(arg0_ptr as *const u8, arg0_len) }
    let arg0 = unsafe { ::std::str::from_utf8_unchecked(arg0) };
    greet(arg0);
}

現在可以看到原始代碼,greet,也就是由#[wasm_bindgen]屬性插入的看起來有意思的函數__wasm_bindgen_generated_greet。這是一個導出函數(用#[export_name]和extern關鍵詞來指定的),參數為JS傳進來的指針/長度對。在函數中它會將這個指針/長度轉換為一個&str (Rust中的一個字符串),然后將它傳遞給我們定義的greet函數。

從另一個方面看,#[wasm_bindgen]屬性生成了兩個wrappers:一個是在JavaScript中將JS類型的轉換為wasm,另外一個是在Rust中接收wasm類型并將其轉為Rust類型。

現在我們來看wrappers的最后一塊,即alert函數。Rust中的greet函數使用標準format!宏來創建一個新的字符串然后傳給alert。回想當我們聲明alert方法的時候,我們是使用 #[wasm_bindgen]聲明的,現在我們看看在這個函數中暴露給rustc的內容:
fn alert(s: &str) {
    #[wasm_import_module = "__wbindgen_placeholder__"]
    extern {
        fn __wbg_f_alert_alert_n(s_ptr: *const u8, s_len: usize);
    }
    unsafe {
        let s_ptr = s.as_ptr();
        let s_len = s.len();
        __wbg_f_alert_alert_n(s_ptr, s_len);
    }
}

這并不是我們寫的,但是我們可以看看它是怎么變成這樣的。alert函數事實上是一個簡化的wrapper,它帶有Rust的 &str然后將它轉換為wasm類型(數字)。它調用了我們在上面看到過的比較有意思的函數__wbg_f_alert_alert_n,然而它奇怪的一點就是#[wasm_import_module]屬性。

在WebAssembly中所有導入的函數都有一個其存在的模塊,而且由于wasm-bindgen構建在ES模塊之上,所以這也將被轉譯為ES模塊導入!

目前__wbindgen_placeholder__模塊實際上并不存在,但它表示該導入將被wasm-bindgen工具重寫,以從我們生成的JS文件中導入。

最后,對于最后一部分的疑惑,我們得到了我們所生成的JS文件,其中包含:
export function __wbg_f_alert_alert_n(ptr0, len0) {
    let arg0 = getStringFromWasm(ptr0, len0);
    alert(arg0)
}

哇! 事實證明,這里隱藏著相當多的東西,我們從JS中的瀏覽器中的警告都有一個相對較長的知識鏈。不過,不要害怕,wasm-bindgen的核心是所有這些基礎設施都被隱藏了! 你只需要在隨便使用幾個#[wasm_bindgen]編寫Rust代碼即可。然后你的JS可以像使用另一個JS包或模塊一樣使用Rust了。

wasm-bindgen還能做什么

wasm-bindgen項目在這個領域內志向遠大,我們在此不再詳細贅述。探索wasm-bindgen中的功能一個有效的方法就是探索示例目錄,這些示例涵蓋了從我們之前看到的Hello World! 到在Rust中對DOM節點的完全操作。

wasm-bindgen高級特性如下:

  • 引入JS結構,函數,對象等來在wasm中調用。你可以在一個結構中調用JS方法,也可以訪問屬性,這給人一種Rust是“原生”的感覺,讓人覺得你曾經寫過的Rust #[wasm_bindgen] annotations都可以連接了起來。
  • 將Rust結構和函數導出到JS。與只用JS使用數字類型來工作相比,你可以導出一個Rust結構并在JS中轉換成一個類。然后可以將結構傳遞,而不是只使用整形數值來傳遞。 smorgasboard 這個例子可以讓你體會支持的互操作特性。
  • 其他各種各樣的特性例如從全局范圍內導入(就像alert函數),在Rust中使用一個Result來獲取JS異常,以及在Rust程序中通用方法模擬存儲JS值。
如果你想了解更多的功能,繼續閱讀 issue tracker

3、wasm-bindgen接下來做什么?

在我們結束之前,我想花一點時間來下描述wasm-bindgen的未來愿景,因為我認為這是當今項目最激動人心的一方面。

不僅僅支持Rust

從第1天起,wasm-bindgen CLI工具就設計成了多語言支持的。盡管Rust目前是唯一被支持的語言,但該工具也可以嵌入C或C++。 #[wasm_bindgen]屬性創建了可被wasm-bindgen工具解析并隨后刪除的輸出(* .wasm)文件的自定義部分。

本節介紹要生成哪些JS綁定以及它們的接口是什么。這個描述中沒有關于Rust的特定部分,因此C ++編譯器插件可以很容易地創建該部分,并通過wasm-bindgen工具進行處理。

我覺得這個方面特別令人振奮,因為我相信它使像wasm-bindgen這樣的工具成為WebAssembly和JS集成的標準做法。希望所有編譯為WebAssembly的語言都能受益,并且可以被bundler自動識別,以避免上述幾乎所有的配置和構建工具。

自動綁定JS生態

使用#[wasm_bindgen] 宏導入功能唯一不好的一面就是你必須將所有東西都寫出來,還要保證沒有任何錯誤。這種讓人覺得很單調(而且易錯)的操作的自動化技術已經成熟了。

所有的web APIs都由WebIDL指定,而且在generate #[wasm_bindgen] annotations from WebIDL是可行的。這個就意味著你不需要像前面一樣定義alert函數,而是你只需要寫下面這些:
#[wasm_bindgen]
pub fn greet(s: &str) {
    webapi::alert(&format!("Hello, {}!", s));
}

在這個例子中,WebIDL對web APIs的描述可以完全自動生成webapi集合,保證沒有錯誤。

我們甚至可以將自動化更進一步,TypeScript組織已經做了這方面的復雜工作,參照generate #[wasm_bindgen] from TypeScript as well。可以免費用npm上的TypeScript自動綁定任何包!

比 JS DOM 操作更快的性能

最后要說的事情對 wasm-bindgen 來說也很重要:超快的 DOM 操作 —— 這是很多 JS 框架的終極目標。如今需要使用一些中間工具來調用 DOM 函數,這些工具正在由 JavaScript 實現轉向 C++ 引擎實現。然而,在 WebAssembly 來臨之后,這些工具并非必須。WebAssembly 是有類型的。

從第一天起,wasm-bindgen 代碼生成的設計就考慮到了將來的宿主綁定方案。當這一特征出現在 WebAssembly 之后,我們可以直接調用導入的函數,而不需要 wasm-bindgen 的中間工具。

此外,它使得 JS 引擎積極優化 WebAssembly 對 DOM 的操作,使其對類型的支持更好,而且在調用 JS 的時候不再需要進行參數驗證。在這一點上,wasm-bindgen 不僅在操作像 string 這樣的富類型變得容易,還提供了一流的 DOM 操作性能。

收工

我自己發現使用WebAssembly是異常令人振奮的,不僅僅是因為其社區,還因為其如此快速地在進度上突飛猛進。wasm-bindgen工具擁有光明的未來。它使JS和諸如Rust這樣的編程語言之間的互操作性變成了一流的體驗,并且隨著WebAssembly的不斷發展它也將提供了長期的好處。

試著給wasm-bindgen一次機會,因功能需求而創建一個問題,亦或繼續保持參與Rust和WebAssembly!

關于Alex Crichton(作者)
Alex是Rust核心團隊的成員之一,自2012年底以來一直從事于Rust。目前他正在幫助WebAssembly Rust Working Group使得Rust + Wasm成為最佳體驗。Alex還幫助維護Cargo(Rust的包管理器),Rust標準庫以及Rust的發布和CI的基礎架構。
來自: oschina
0
0
評論 共 1 條 請登錄后發表評論
1 樓 xxbb77 2018-11-12 16:32
非常感謝 謝謝分享

發表評論

您還沒有登錄,請您登錄后再發表評論

相關推薦

  • 深入認識javascript中得eval函數

    深入認識javascript中得eval函數深入認識javascript中得eval函數深入認識javascript中得eval函數

  • 深入淺出Rust

    Rust是一門新的編程語言。 我想,大部分讀者看到本書,估計都會不約而同地想到同樣的問 題:現存的編程語言已經多得數不清了,再發明一種新的編程語言有何 意義?難道現存的那么多編程語言還不夠用嗎,發明一種新的編程語言 能解決什么新問題? 俗話說,工欲善其事,必先利其器。在程序員平時最常用的工具排 行榜中,編程語言當仁不讓的是最重要的“器”。編程語言不僅是給程序 設計者使用的工具,反過來,它也深刻地影響了設計者本身的思維方式 和開發習慣。 卓越的編程語言,可以將優秀的設計、先進的思想、成功的經驗, 自然而然地融入其中,使更多的使用者開闊眼界、拓展思路,受益無 窮

  • 深入淺出Rust.范長春(帶完整書簽文字版).pdf

    本書詳細描述了Rust語言的基本語法,穿插講解一部分高級使用技巧,并以更容易理解的方式解釋其背后的設計思想。全書總共分五個部分。 第一部分介紹Rust基本語法,因為對任何程序設計語言來說,語法都是基礎,學習這部分是理解其他部分的前提。 第二部分介紹屬于Rust獨一無二的內存管理方式。它設計了一組全新的機制,既保證了安全性,又保持了強大的內存布局控制力,而且沒有額外性能損失。這部分是本書的重點和核心所在,也是Rust語言的思想內核精髓之處。 第三部分介紹Rust的抽象表達能力。它支持多種編程范式,以及較為強大的抽象表達能力。 第四部分介紹并發模型。在目前這個階段,對并行編程的支持是新一代編程語言不可繞過的重要話題。Rust也吸收了業界最新的發展成果,對并發有良好支持。 第五部分介紹一些實用設施。Rust語言有許多創新,但它絕不是高高在上孤芳自賞的類型,設計者在設計過程中充分考慮了語言的工程實用性。眾多在其他語言中被證明過的優秀實踐被吸收了進來,有利于提升實際工作效率。 通過此書,讀者能夠深入透徹地理解Rust的高階特性,比如代數類型系統、生命周期、借用檢查、內部可變性、線程安全、泛型、閉包、迭代器、生成器等。可作為參考書供學生、軟件工程師、研究人員以及其他對Rust語言感興趣的讀者參考。本書所揭示的Rust編程語言的設計思想對于理解其他系統編程語言,如C++,也非常有幫助。 目錄 前言 第一部分 基礎知識 第1章 與君初相見 2 1.1 版本和發布策略 2 1.2 安裝開發環境 4 1.3 Hello World 7 1.4 Prelude 8 1.5 Format格式詳細說明 8 第2章 變量和類型 10 2.1 變量聲明 10 2.1.1 變量遮蔽 12 2.1.2 類型推導 13 2.1.3 類型別名 14 2.1.4 靜態變量 15 2.1.5 常量 16 2.2 基本數據類型 16 2.2.1 bool 16 2.2.2 char 17 2.2.3 整數類型 17 2.2.4 整數溢出 19 2.2.5 浮點類型 21 2.2.6 指針類型 23 2.2.7 類型轉換 23 2.3 復合數據類型 24 2.3.1 tuple 25 2.3.2 struct 25 2.3.3 tuple struct 27 2.3.4 enum 29 2.3.5 類型遞歸定義 32 第3章 語句和表達式 34 3.1 語句 34 3.2 表達式 34 3.2.1 運算表達式 35 3.2.2 賦值表達式 37 3.2.3 語句塊表達式 38 3.3 if-else 39 3.3.1 loop 40 3.3.2 while 41 3.3.3 for循環 42 第4章 函數 44 4.1 簡介 44 4.2 發散函數 46 4.3 main函數 47 4.4 const fn 48 4.5 函數遞歸調用 49 第5章 trait 50 5.1 成員方法 50 5.2 靜態方法 53 5.3 擴展方法 55 5.4 完整函數調用語法 56 5.5 trait約束和繼承 58 5.6 Derive 59 5.7 trait別名 60 5.8 標準庫中常見的trait簡介 61 5.8.1 Display和Debug 61 5.8.2 PartialOrd / Ord / PartialEq / Eq 62 5.8.3 Sized 63 5.8.4 Default 64 5.9 總結 65 第6章 數組和字符串 66 6.1 數組 66 6.1.1 內置方法 67 6.1.2 多維數組 67 6.1.3 數組切片 67 6.1.4 DST和胖指針 68 6.1.5 Range 70 6.1.6 邊界檢查 72 6.2 字符串 74 6.2.1 &str; 74 6.2.2 String 75 第7章 模式解構 77 7.1 簡介 77 7.2 match 78 7.2.1 exhaustive 79 7.2.2 下劃線 80 7.2.3 match也是表達式 82 7.2.4 Guards 83 7.2.5 變量綁定 84 7.2.6 ref和mut 85 7.3 if-let和while-let 88 7.4 函數和閉包參數做模式解構 89 7.5 總結 90 第8章 深入類型系統 91 8.1 代數類型系統 91 8.2 Never Type 94 8.3 再談Option類型 97 第9章 宏 102 9.1 簡介macro 102 9.1.1 實現編譯階段檢查 102 9.1.2 實現編譯期計算 103 9.1.3 實現自動代碼生成 103 9.1.4 實現語法擴展 103 9.2 示范型宏 103 9.3 宏1.1 105 第二部分 內存安全 第10章 內存管理基礎 110 10.1 堆和棧 110 10.2 段錯誤 111 10.3 內存安全 112 第11章 所有權和移動語義 114 11.1 什么是所有權 114 11.2 移動語義 116 11.3 復制語義 118 11.4 Box類型 120 11.5 Clone VS. Copy 121 11.5.1 Copy的含義 121 11.5.2 Copy 的實現條件 121 11.5.3 Clone的含義 122 11.5.4 自動derive 123 11.5.5 總結 123 11.6 析構函數 124 11.6.1 資源管理 125 11.6.2 主動析構 126 11.6.3 Drop VS. Copy 129 11.6.4 析構標記 129 第12章 借用和生命周期 132 12.1 生命周期 132 12.2 借用 132 12.3 借用規則 134 12.4 生命周期標記 136 12.4.1 函數的生命周期標記 136 12.4.2 類型的生命周期標記 138 12.5 省略生命周期標記 139 第13章 借用檢查 141 13.1 編譯錯誤示例 142 13.2 內存不安全示例:修改枚舉 143 13.3 內存不安全示例:迭代器 失效 144 13.4 內存不安全示例:懸空指針 146 13.5 小結 148 第14章 NLL(Non-Lexical- Lifetime) 150 14.1 NLL希望解決的問題 150 14.2 NLL的原理 154 14.3 小結 157 第15章 內部可變性 158 15.1 Cell 158 15.2 RefCell 161 15.3 UnsafeCell 164 第16章 解引用 169 16.1 自定義解引用 169 16.2 自動解引用 171 16.3 自動解引用的用處 171 16.4 有時候需要手動處理 173 16.5 智能指針 175 16.5.1 引用計數 175 16.5.2 Cow 178 16.6 小結 180 第17章 泄漏 181 17.1 內存泄漏 181 17.2 內存泄漏屬于內存安全 184 17.3 析構函數泄漏 185 第18章 Panic 190 18.1 什么是panic 190 18.2 Panic實現機制 191 18.3 Panic Safety 192 18.4 小結 197 第19章 Unsafe 198 19.1 unsafe關鍵字 198 19.2 裸指針 199 19.3 內置函數 201 19.3.1 transmute 201 19.3.2 內存讀寫 202 19.3.3 綜合示例 204 19.4 分割借用 206 19.5 協變 209 19.5.1 什么是協變 209 19.5.2 PhantomData 211 19.6 未定義行為 214 19.7 小結 215 第20章 Vec源碼分析 216 20.1 內存申請 217 20.2 內存擴容 220 20.3 內存釋放 222 20.3.1 Vec的析構函數 222 20.3.2 Drop Check 223 20.4 不安全的邊界 226 20.5 自定義解引用 227 20.6 迭代器 228 20.7 panic safety 231 第三部分 高級抽象 第21章 泛型 234 21.1 數據結構中的泛型 234 21.2 函數中的泛型 235 21.3 impl塊中的泛型 237 21.4 泛型參數約束 237 21.5 關聯類型 241 21.6 何時使用關聯類型 244 21.7 泛型特化 246 21.7.1 特化的意義 247 21.7.2 default上下文關鍵字 248 21.7.3 交叉 impl 250 第22章 閉包 252 22.1 變量捕獲 254 22.2 move關鍵字 256 22.3 Fn/FnMut/FnOnce 257 22.4 閉包與泛型 259 22.5 閉包與生命周期 261 第23章 動態分派和靜態分派 264 23.1 trait object 265 23.2 object safe 268 23.3 impl trait 271 第24章 容器與迭代器 275 24.1 容器 275 24.1.1 Vec 275 24.1.2 VecDeque 277 24.1.3 HashMap 277 24.1.4 BTreeMap 281 24.2 迭代器 283 24.2.1 實現迭代器 283 24.2.2 迭代器的組合 284 24.2.3 for循環 285 第25章 生成器 289 25.1 簡介 289 25.2 對比迭代器 291 25.3 對比立即求值 292 25.4 生成器的原理 293 25.4.1 生成器原理簡介 293 25.4.2 自引用類型 297 25.5 協程簡介 298 第26章 標準庫簡介 302 26.1 類型轉換 302 26.1.1 AsRef / AsMut 302 26.1.2 Borrow / BorrowMut 303 26.1.3 From / Into 304 26.1.4 ToOwned 305 26.1.5 ToString / FromStr 305 26.2 運算符重載 306 26.3 I/O 308 26.3.1 平臺相關字符串 308 26.3.2 文件和路徑 309 26.3.3 標準輸入輸出 310 26.3.4 進程啟動參數 311 26.4 Any 311 第四部分 線程安全 第27章 線程安全 314 27.1 什么是線程 314 27.2 啟動線程 316 27.3 免數據競爭 317 27.4 Send & Sync 320 第28章 詳解Send和Sync 321 28.1 什么是Send 321 28.2 什么是Sync 322 28.3 自動推理 323 28.4 小結 324 第29章 狀態共享 325 29.1 Arc 325 29.2 Mutex 326 29.3 RwLock 328 29.4 Atomic 329 29.5 死鎖 331 29.6 Barrier 333 29.7 Condvar 334 29.8 全局變量 335 29.9 線程局部存儲 336 29.10 總結 337 第30章 管道 339 30.1 異步管道 339 30.2 同步管道 341 第31章 第三方并行開發庫 343 31.1 threadpool 343 31.2 scoped-threadpool 344 31.3 parking_lot 345 31.4 crossbeam 345 31.5 rayon 346 第五部分 實用設施 第32章 項目和模塊 350 32.1 cargo 350 32.2 項目依賴 353 32.2.1 配置 355 32.2.2 workspace 355 32.2.3 build.rs 356 32.3 模塊管理 358 32.3.1 文件組織 358 32.3.2 可見性 360 32.3.3 use關鍵字 362 第33章 錯誤處理 364 33.1 基本錯誤處理 364 33.2 組合錯誤類型 366 33.3 問號運算符 367 33.4 main函數中使用問號運算符 372 33.5 新的Failure庫 373 第34章 FFI 375 34.1 什么是FFI 375 34.2 從C調用Rust庫 376 34.3 從Rust調用C庫 378 34.4 更復雜的數據類型 378 第35章 文檔和測試 381 35.1 文檔 381 35.2 測試 382 附錄 詞匯表 387

  • 全方位深入理解JavaScript面向對象

    JavaScript面向對象程序設計 本文會碰到的知識點: 原型、原型鏈、函數對象、普通對象、繼承 讀完本文,可以學到 面向對象的基本概念 JavaScript對象屬性 理解JavaScript中的函數對象與普通對象 理解prototype和proto 理解原型和原型鏈 詳解原型鏈相關的Object方法 了解如何用ES5模擬類,以及各種方式的優缺點 了解如何用ES6實現面向對象 目錄...

  • 深入認識CPU

    學習匯編的時候,對cpu的認識有助于對匯編語言的理解,因為匯編語言功能可以直接對cpu中的寄存器進行操作。 以8086cpu為例子,8086cpu是16位的,那么16位cpu具有哪些性質呢? 運算器一次最多可以處理16位的數據 寄存器的最大寬度為16位 寄存器和運算器之間的通路為16位 1.cpu組成 控制部件單元(Control unit):主要是負責對指令,并且發出為完成每條指令所要執行的各個

  • Rust 程序設計語言(第二版).pdf

    Rust 程序設計語言(第二版).pdf 學習rust必備,rust是mozilla開發,rust的作者也是javascript的作者。

  • 打敗 Python、JS、C# 成最受歡迎編程語言,是時候掌握 Rust 了嗎?

  • 對html,css,和JavaScript的粗淺認識

    1.css是層疊樣式表,負責給文檔描述樣式; ?2.css就是給html穿衣服的,我們把網頁視為人,html就是身體,css就是衣服,JavaScript就是言行舉止;

  • 互操作性(筆記)

  • Rust: 億元估值AI網紅代碼的不同版本

    Rust版本 use std::io; /* AI 核心代碼 --rust 版本 估值 1個億 */ fn main() { loop { let mut str_in = String::new(); io::stdin() .read_line(&mut str_in) .ok() ...

  • IOT語義互操作性之語義

    這個系列文章描述了一個單一的語義數據模型來支持物聯網和建筑、企業和消費者的數據轉換。 這種模型必須簡單可擴展, 以便能夠在各行業領域之間實現插件化和互操作性。 對于一個目前從事智能硬件的老碼農,覺得這...

  • rust 網絡爬蟲相關收集

    Hyper :一個快速和正確的 Rust HTTP實現。 https://github.com/hyperium/hyper html5ever:Rust html解析庫 https://github.com/servo/html5ever 附:https://github.com/carllerche/curl-rust ...

  • 隨便談談Rust錯誤處理

    錯誤處理? 其實我一直不能太分清楚什么是錯誤什么是異常,不過我倒是覺得區分這些個東西意義不大,重要的是認清本質。一個程序在運行過程中總會碰到一些錯誤,有的是因為用戶的不當操作,有的是因為期望的結果沒有發生,當然還有直接就是無法恢復的程序bug,無論如何,這些問題,如果我們考慮到了,都是需要一套解決方案的,所以我們就來稍微談談這些解決方法,還有我最近學到Rust的解決方法。 從Error Cod...

  • 對JDK的深入理解

  • 計算機各部件認識

  • TCP/UDP深入理解

  • tigase深入理解xmpp服務器-概念總覽

    Tigase是基于組件,插件,連接器實現的框架,Tigase提供了及其靈活的接口,供我們實現自定義組件,插件,連接器。1、組件:是側重實現功能的,例如發布訂閱,Socks5代理,開發者可以為組件配置獨立的數據庫,統計信息等,具體可見開發文檔。組件是Tigase服務器的主要元素。組件是一段更大的代碼,可以具有單獨的地址,接收和發送節,并配置為響應眾多事件。為Tigase服務器實現的示例組件包括:c2...

  • 2019 年,Rust 與 WebAssembly 將讓 Web 開發更美好

    作者 |Nick Fitzgerald譯者 |彎月責編 | 屠敏出品 |CSDN(ID:CSDNNews)將 Rust 編譯成 WebAssembly 應該是快速且...

  • rust 的內存管理

  • IOT語義互操作性之本體論

    這個系列文章描述了一個單一的語義數據模型來支持物聯網和建筑、企業和消費者的數據轉換。 這種模型必須簡單可擴展, 以便能夠在各行業領域之間實現插件化和互操作性。 對于一個目前從事智能硬件的老碼農,覺得這...

Global site tag (gtag.js) - Google Analytics pk10缩号工具手机版 河池市| 东宁县| 崇左市| 启东市| 南阳市| 木兰县| 西峡县| 年辖:市辖区| 科技| 太和县| 永仁县| 卢氏县| 龙泉市| 原阳县| 酉阳| 鄂伦春自治旗| 集安市| 分宜县| 金山区| 通许县| 达日县| 舟山市| 丰都县| 新巴尔虎左旗| 义马市| 深圳市| 英超| 丰顺县| 榆树市| 鹰潭市| 美姑县| 龙南县| 咸宁市| 隆子县| 甘孜| 金溪县| 云龙县| 浦江县|