編者按:高可用架構分享及傳播在架構領域具有典型意義的文章,本文由唐劉在高可用架構群分享情萤。轉(zhuǎn)載請注明來自高可用架構公眾號「 ArchNotes 」鸭蛙。
唐劉,PingCAP 首席架構師筋岛,現(xiàn)致力于下一代分布式數(shù)據(jù)庫 TiDB娶视、分布式存儲 TiKV 的開發(fā)。開源愛好者,Go肪获、Rust 等語言愛好者和實 踐者寝凌。
大家好,我是 PingCAP 的唐劉孝赫,今天很榮幸跟大家來分享一下 Rust 相關知識以及我們團隊使用 Rust 的實戰(zhàn)經(jīng)驗较木。
為什么選擇Rust
首先來說說最近 Go 社區(qū)討論比較多的事情,Dropbox 將底層的類 S3 服務改用 Rust 來重寫了青柄,一下子讓 Rust 增加了很多知名度伐债,誰叫 Dropbox 這種公司通常都是技術架構上面的風向標。大家普通關注的一個問題:
為什么 Dropbox 不用 Go刹前,反而用一門學習曲線比較陡峭的 Rust 來進行開發(fā)泳赋?
其實這個問題也同樣適用于我們,一個自認為 Go 經(jīng)驗非常豐富的團隊喇喉,為什么不用 Go 反而要選擇 Rust祖今?
介紹一下我們在做的事情。我們團隊從事的是下一代分布式數(shù)據(jù)庫的開發(fā)拣技,也就是俗稱的 NewSQL千诬,整個理論基礎基于 Google 的 F1 以及 Spanner,所以自然我們的 NewSQL 也是分成了兩塊膏斤,一個是無狀態(tài)的 SQL 層徐绑,也就是現(xiàn)階段已經(jīng)開源出來的 TiDB(http://dwz.cn/2XZkSm),另一個就是分布式 KV 層莫辨,我們叫做 TiKV傲茄,預計會在4月份開源。
TiDB 是使用 Go 編寫的沮榜,熟悉 Go 的同學都應該知道盘榨,用 Go 來寫分布式應用那是非常的快捷方便的,而且我們團隊的成員都有非常深厚的 Go 編程經(jīng)驗蟆融,但是在決定做 TiKV 的時候草巡,我們沒有使用 Go,或者使用 C++型酥,Java 這些更流行的靜態(tài)語言山憨,反而是選擇了一門我們自身完全不熟悉的語言 Rust,Why弥喉?
先來說說使用 Go 會遇到的問題:
GC郁竟,雖然 1.6 之后 Go 的 GC 已經(jīng)改善的很好了,而且我們覺得以后會越來越好由境,但是對于一個對性能要求非常高的分布式應用枪孩,我們傾向選擇一門沒有 GC 的語言,這樣在內(nèi)存上面更加可控。
Cgo蔑舞,TiKV 使用 RocksDB 作為其底層存儲 engine,如果用 Go嘹屯,我們需要使用 Cgo 來進行 RocksDB的調(diào)用攻询,而 Cgo 對性能還是有比較大的損耗的。
再來說說不選擇 C++ 或者 Java州弟,C++ 主要是大規(guī)模開發(fā)對整個團隊要求非常高钧栖,而我們自己也覺得用 C++ 不可能 hold 住在短時間內(nèi)做出產(chǎn)品,所以自然放棄婆翔。而 Java拯杠,我們團隊沒幾個人精通 Java,也直接放棄了啃奴。
所以潭陪,我們最終將目光落到了 Rust 上面,主要在于 Rust 有幾個很 cool 的 feature最蕾,就是 type safety依溯,memory safety 以及 thread safety,這個后續(xù)詳細說明瘟则。
Rust 的基礎入門
在 Rust 的官網(wǎng)上面黎炉,我們可以看到 Rust 的介紹,它是一門系統(tǒng)編程語言醋拧,性能好慷嗜,同時在編譯階段就能幫你檢測出內(nèi)存,多線程數(shù)據(jù)訪問等問題丹壕,保證程序安全健壯庆械。
也就是說,使用 Rust 寫程序雀费,如果能通過編譯干奢,你就不用擔心類似 C++ 里面很多 memory leak,segment faut盏袄,data race 的問題了忿峻,但這一切都是有代價的。Rust 上手非常不容易辕羽,難度可以跟 C++ 媲美逛尚,如果是 Go,沒準學習一個星期都能開始給項目貢獻代碼刁愿,但換成 Rust绰寞,可能一個月都還在跟編譯器作斗爭,研究為啥自己的代碼編譯不過。
因為我不清楚大家有多少人接觸過 Rust滤钱,所以這里列出來一些例子觉壶,讓大家對 Rust 的語法有一個基本了解。
首先就是最通用的 Hello world:
(點擊圖片可全屏縮放圖片)
fn 是 Rust 的關鍵字件缸,用來定義函數(shù)铜靶,函數(shù)名字是 main, println! 是一個 macro,在 rust style 里面他炊,macro 都是在末尾使用“!”來表示的争剿。
我們接下來定義幾個變量,下面就開始顯示出 rust 跟其他語言的不一樣的地方了:
(點擊圖片可全屏縮放圖片)
上面我們聲明了一個 u32 類型的變量痊末,但是沒有初始化蚕苇,然后打印它的值,在一些語言里面凿叠,譬如 Go涩笤,會打印出 0,但是在 Rust 里面幔嫂,這沒法編譯通過辆它,編譯器會提示:
(點擊圖片可全屏縮放圖片)
上面的錯誤告訴我們使用了一個沒有初始化的變量,我們先來初始化一下履恩,變成這樣:
(點擊圖片可全屏縮放圖片)
上面我們首先定義了一個初始值為 0 的變量锰茉,然后改成 10 打印,編譯切心,發(fā)現(xiàn)如下錯誤:
(點擊圖片可全屏縮放圖片)
這次編譯器告訴我們對一個 immutable 的變量進行了更改飒筑。在 Rust 里面,變量是分為 immutable 和 mutable 的绽昏,我們必須顯示地定義這個變量到底能不能改動协屡。我們使用 mut 關鍵字來告訴 Rust 這個變量是 mutable 的,如下:
(點擊圖片可全屏縮放圖片)
這下就能正常編譯了全谤。
通過上面一些簡單的例子肤晓,大家應該對 Rust 有了一個初步的印象,更加詳細的了解可以去參考官網(wǎng)认然。
讓 Rust 開發(fā)變 easy 的關鍵技術點
前面在為什么選擇 Rust 里面补憾,我提到了因為 Rust 有幾個很 cool 的特性,能讓我們寫出不容易出錯的并發(fā)程序卷员。而且我認為盈匾,只要理解掌握了這個關鍵點,用 Rust 進行程序開發(fā)就很 easy了毕骡。
Type safety
Rust 是一門嚴格要求類型安全的語言削饵,在 C/C++ 的世界里面岩瘦,我們可以無拘無束的進行類型轉(zhuǎn)換,譬如:
(點擊圖片可全屏縮放圖片)
這種在 C/C++ 里面很常見的處理方式窿撬,在 Rust 里面是不被允許的启昧,譬如:
我們會得到如下編譯錯誤:
如果強制做這種內(nèi)存轉(zhuǎn)換,我們可以使用 unsafe劈伴,顯示的告訴 Rust 這么做是不安全的箫津,但是你別管了:
(點擊圖片可全屏縮放圖片)
通常情況下面,Rust 是不允許寫上面這樣的代碼的宰啦,所以它將 unsafe 的選擇權顯示的交給了程序員,而我們通過 unsafe 也能清晰的知道哪里是不安全的代碼饼拍,需要注意的赡模。
Memory safety
下面進入 Rust 最令人抓狂的一個關鍵點了。Rust 是能夠保證程序的 memory safety 的师抄,那么是如何保證的呢漓柑?首先我們需要了解的是 Rust 里面 ownership 以及 move 的概念。
Ownership + move
在Rust里面叨吮,任何資源只可能有一個 ownership辆布,譬如一個最簡單的例子:
這里我們使用 let 將一個 vector 給綁定到 a 這個變量上面了,我們就可以認為 a 現(xiàn)在是這個 vector 的 ownership茶鉴。然后對于這個 vector 的 resouce锋玲,同一個時間只允許一個 ownership。我們來看下面這個代碼:
(點擊圖片可全屏縮放圖片)
在上面的例子中涵叮,我們將 a 賦值給了 b惭蹂,同時繼續(xù)打印 a[0] 的值,這個在大多數(shù)語言都沒有任何問題的操作割粮,在 Rust 里面盾碗,是會報錯的,如下:
為什么呢舀瓢?在打印 a[0] 之前廷雅,我們進行了 let b = a 這樣的操作,這個操作京髓,在 Rust 里面叫做 move航缀,含義就是把 a 對 vector 的 ownership 移交給了 b,a 放棄了對 vector 的 ownership朵锣。因為 a 已經(jīng)對這個 vector 沒有 ownership 了谬盐,自然就不能訪問相關的數(shù)據(jù)了。
ownership 和 move 的概念應該算是學習 Rust 第一個坑诚些,我們也很容易寫出如下代碼:
(點擊圖片可全屏縮放圖片)
這個代碼照樣是編譯不過的飞傀,因為 do_vec 這個函數(shù)皇型,a 已經(jīng)將對 vector 的 ownership 給 move 了。
所以通常我們只要看到 let b = a 這樣的代碼砸烦,就表明 a move 掉了 ownership 了弃鸦,但有一個例外,如果a的類型實現(xiàn)了copy trait幢痘,let b =a 就不是move唬格,而是 copy 了,下面的代碼是能正常編譯的:
上面的代碼里面颜说,let b = a购岗,a 并沒有 move,而是將自己的數(shù)據(jù) copy 了一份給 b 使用门粪。通澈盎基本的數(shù)據(jù)類型都是實現(xiàn)了 copy trait,當然我們也可以將我們自定義的類型實現(xiàn) copy玄妈,只是就需要權衡下 copy 的性能問題了乾吻。
Borrow
前面我們舉了一個 do_vec 的例子,如果真的需要在調(diào)用這個函數(shù)之后繼續(xù)使用這個 vector拟蜻,怎么辦呢绎签?
這里我們就開始接觸到了第二個坑,borrow酝锅。上面說了诡必,move 是我給你了 ownership,而 borrow 則是我借給你這個 resource 的使用權屈张,到時候還要還給我:
(點擊圖片可全屏縮放圖片)
上面的例子中擒权,我們在參數(shù)里面使用了 & 來表示 borrow,do_vec 這個函數(shù)只是借用了 a阁谆,然后函數(shù)結束之后碳抄,還了回來,這樣后續(xù)我們就能繼續(xù)使用 a 了场绿。
既然 borrow剖效,當然就能用了,于是我們就可能寫這樣的代碼:
然后 Rust 又華麗麗的報錯了焰盗,輸出:
因為我們的 borrow 只是 immutable 的 borrow璧尸,并不能改數(shù)據(jù)。在前面我們也提到過熬拒,如果要對一個變量進行修改爷光,必須顯示的用 mut 進行聲明,borrow 也是一樣澎粟,如果要對一個 borrow 的東西顯示修改蛀序,必須使用 mutable borrow欢瞪,也就是這樣:
(點擊圖片可全屏縮放圖片)
borrow 還有 scope 的概念,有時候我們寫這樣的代碼:
(點擊圖片可全屏縮放圖片)
發(fā)現(xiàn)編譯器又報錯了徐裸,輸出:
因為我們之前用 y 來對 x 進行了mutable 的 borrow遣鼓,但是還沒還回去,所以后面 immutable的 borrow 就不允許重贺。這個我們可以通過 scope 來顯示的控制 mutable 的生存周期:
(點擊圖片可全屏縮放圖片)
這樣在 printIn! 進行 immutable 的 borrow 的時候骑祟,y 這個mutable 的 borrow 已經(jīng)還回來了。
一個變量气笙,可以同時進行多個 immutable 的 borrow次企,但只允許一個 mutable 的 borrow,這個其實跟 read-write lock 很相似潜圃,同時允許多個讀鎖抒巢,但一次只允許一個寫鎖。
Lifetime
在 C++ 里面秉犹,相信大家對野指針都印象深刻,有時候稚晚,我們會引用了一個已經(jīng)被 delete 的對象崇堵,然后再次使用的時候就 panic 了。在 Rust 里面客燕,是通過 lifetime 來解決這個問題的鸳劳,不過引入了 lifetime 之后,代碼看起來更丑了也搓。一個簡單的例子:
(點擊圖片可全屏縮放圖片)
我們定義了一個 struct赏廓,里面的 field b 是對外面一個 u32 變量的引用,而這個引用的 lifetime是 ’a傍妒。使用 lifetime 能保證b 引用的 u32 數(shù)據(jù)的生存周期一定是大于 A 的幔摸。
但是在上面的例子中,我們在一個 scope 里面颤练,讓 b 引用了 c既忆,但是 c 在 scope 結束之后就沒了,這時候 b 就是一個無效的引用了嗦玖,所以 Rust 會編譯報錯:
Thread safety
前面我們提到患雇,Rust 使用 move,borrow 以及 lifetime 這些機制來保證 memory safety宇挫,雖然這幾個概念不怎么好理解苛吱,而且很容易大家寫代碼的時候就會陷入與編譯器的斗爭,但是我個人覺得只要理解了這些概念器瘪,寫 Rust 就不是問題了翠储。
好了绘雁,說完了 memory safety,我們馬上進入 thread safety了彰亥。大家都知道咧七,多線程的程序很難寫,有且稍微不注意任斋,就會出現(xiàn) data race 等情況继阻,導致數(shù)據(jù)錯誤,而且偏偏這樣的 bug 還能難查出來废酷。
譬如在 Go 里面瘟檩,我們可以這樣:
(點擊圖片可全屏縮放圖片)
上面的例子很極端,大家應該也不會這面寫代碼澈蟆,但實際中墨辛,我們?nèi)匀豢赡軙媾R data race 的問題。雖然 Go 可以通過 --race 打開 data race 的檢查趴俘,可通常只會用于 test睹簇,而不會在線上使用。
而 Rust 則是在源頭上面完全讓大家沒法寫出 data race 的代碼寥闪。首先我們先來了解 Rust 兩個針對并發(fā)的 trait太惠,Send和 Sync:
-
Send
當一個類型實現(xiàn)了 Send,我們就可以認為這個類型可以安全的從一個線程 move 給另一個線程去使用疲憋。
-
Sync
當一個類型實現(xiàn)了 Sync凿渊,我們就可以認為這個類型可以在多線程里面通過 shared reference(也就是 Arc)安全的使用。
上面的概念看起來比較困惑缚柳,簡單一點就是如果一個類型實現(xiàn)了Send + Sync埃脏,那么這個就能在多線程下面安全的使用。
先來看一個簡單的例子:
(點擊圖片可全屏縮放圖片)
上面就是一個典型的多線程 data race 的問題了秋忙,Rust 是編譯不過的彩掐,報錯:
前面說了,我們可以通過 Arc 來保證自己的類型在多線程下面安全使用灰追,我們加上 Arc佩谷。
(點擊圖片可全屏縮放圖片)
現(xiàn)在我們的 vector 能多線程訪問了,但是仍然出錯:
(點擊圖片可全屏縮放圖片)
因為我們不光是要多線程 read监嗜,而且還需要多線程去 write谐檀,自然 Rust 不允許,所以我們需要顯示的進行加鎖保護裁奇,如下:
(點擊圖片可全屏縮放圖片)
所以桐猬,如果我們要對一個數(shù)據(jù)進行安全的多線程使用,最通用的做法就是使用 Arc<Mutex<T>> 或者 Arc<RwLock<T>>進行封裝使用刽肠。
當然溃肪,除了 Arc + Lock 之外免胃,Rust 還提供了 channel 機制方便進行線程之間的數(shù)據(jù)通訊,channel 類似于 Go 的 channel惫撰,一端 send羔沙,一端 recv,這里就不詳細說明了厨钻。
這里在提一點扼雏,因為在 Rust 里面,對于多線程使用的數(shù)據(jù)夯膀,我們必須明確的進行 lock 保護诗充,這個編程風格直接帶到了后來我們寫 Go 。在 Go 里面诱建,我以前寫 lock蝴蜓,通常會這樣:
(點擊圖片可全屏縮放圖片)
使用一個 mutex 變量 m 來對數(shù)據(jù) v1,v2 進行多線程保護俺猿,但這種寫法其實很容易就容易忘記這個 lock 到底要保護哪些數(shù)據(jù)茎匠。自從受 Rust 影響了之后,我就喜歡寫成這樣了:
(點擊圖片可全屏縮放圖片)
上面就是顯示的將 lock 以及需要保護的數(shù)據(jù)放到一個 struct 里面押袍,大家一看代碼就知道這個 lock 要保護哪些數(shù)據(jù)了汽抚。
Rust 開發(fā)實戰(zhàn)經(jīng)驗
前面說了是 Rust 的一些基本 feature,這里開始說下我們項目中用 Rust 的相關經(jīng)驗伯病。
Cargo
如果要用 Rust進行項目開發(fā),首先就需要了解的就是 Cargo否过,Cargo 是 Rust 一個構建以及包管理工具午笛,現(xiàn)在應該已經(jīng)成了 Rust 開發(fā)項目的規(guī)范了。Cargo 的使用還是很簡單的苗桂,大家可以直接去看瀏覽官網(wǎng) (https://crates.io/)药磺。
quick_error!
最開始,我們在寫 C 程序的時候煤伟,通過定義不同的 int 返回值來表示一個函數(shù)是不是有 error癌佩。然后到了 C++,我們就可以通過 expection 來處理 error 了便锨。不過到底采用哪種標準围辙,都是沒有定論的。
到了 Go放案,直接約定了函數(shù)最后一個返回參數(shù)是 error姚建,官方還有一篇 blog 來介紹了 Go 的error handling (http://blog.golang.org/error-handling-and-go)。
在 Rust 里面吱殉,error 也有相應的處理規(guī)范掸冤,就是 Result厘托,Result 是一個 enum,定義是這樣的:
(點擊圖片可全屏縮放圖片)
也就是說稿湿,我們的函數(shù)都可以返回 Result铅匹,外面去判斷,如果是 Ok饺藤,那么就是正確的處理包斑,如果是 Err 則是錯誤了。
這里有篇 error handling 的詳細說明 (https://doc.rust-lang.org/book/error-handling.html)策精。
通常大家都會按照上面的規(guī)范來處理 error舰始,也就是定義自己的 error,實現(xiàn)其他 error 轉(zhuǎn)成自己 error 的 from 函數(shù)咽袜,然后在使用 try! 在代碼里面簡化 error 的處理丸卷。
但是很快我們就發(fā)現(xiàn)了一個很嚴重的問題,定義自己的 error询刹,以及將其他 error 轉(zhuǎn)成我們對應的 error 是一件非常冗余復雜的事情谜嫉,所以我們使用 quick_error!(http://dwz.cn/2XZpNo)來簡化整個流程。
Clippy
當我第一次寫 Go 代碼的時候凹联,我對 Go 的 fmt 印象特別深刻沐兰,以后再也不用擔心編碼風格的爭論了,Rust 也有相關的 rust fmt蔽挠,但是更令我驚奇的是 Rust 的 Clippy 這個工具住闯。Clippy 已經(jīng)不是糾結于編碼風格了,而是直接告訴你代碼要這么寫澳淑,那么寫不對比原。
一個很簡單的例子:
(點擊圖片可全屏縮放圖片)
這個代碼是能編譯通過的,但是如果我們打開了 Clippy 的支持杠巡,直接會提示:
(點擊圖片可全屏縮放圖片)
也就是告訴你量窘,別用 to_string,用 to_owned氢拥。
我們都知道蚌铜,要開發(fā)一個高性能的網(wǎng)絡服務,通常的選擇就是 epoll 這種基于事件觸發(fā)的網(wǎng)絡模型嫩海,在 Rust冬殃,現(xiàn)階段成熟的庫就是 MIO。MIO是一個異步 IO 庫叁怪,對不同的操作系統(tǒng)提供了統(tǒng)一抽象支持造壮,譬如 Linux 下面就是 epoll,UNIX 下面就是 kqueue,Windows 下是 IOCP耳璧。不過 MIO 為了統(tǒng)一擴平臺成箫,在一些實現(xiàn)上面做了妥協(xié)。
MIO
譬如在 Linux 下面旨枯,系統(tǒng)直接提供了 event fd 的支持蹬昌,但 MIO 為了兼容 UNIX,使用了傳統(tǒng)的 pipe 而不是 event fd 來進行 event loop 的 awake 處理攀隔。
這里在單獨說下 MIO 提供的另一種線程通訊 channel 機制皂贩,雖然我們可以用 Rust 自己的 thread channel 來進行線程通訊阅畴,但如果引入 MIO罚渐,我更喜歡用 MIO 自己的 channel,主要原因是采用的 lock free queue拇厢,性能更好满粗,但有 queue size 限制問題辈末,發(fā)送太頻繁但接受端沒處理過來,就會造成發(fā)送失敗的問題了映皆。
Rust 語言的美中不足
我們團隊已經(jīng)使用 Rust進行了幾個月的開發(fā)挤聘,當然也遇到了一些很不爽的地方。
首先就是庫的不完善捅彻,相比于 Go组去,Rust 的庫真的太不完備了。我覺得現(xiàn)階段 Rust 仍然沒有大規(guī)模的應用步淹,lib 不完備占了很大一個原因从隆。
TiKV 是一個服務器程序,自然就會涉及到網(wǎng)絡編程缭裆,官方現(xiàn)階段的 net mod 里面键闺,只有 block socket 的支持,這個完全沒法用來開發(fā)高性能網(wǎng)絡程序的幼驶。幸好有 MIO,但光有 MIO 是遠遠不夠韧衣,在 Go 里面盅藻,我們很方便的使用 gRPC 來進行 RPC 的編寫,但是在 Rust 里面畅铭,我覺得還得在等很長一段時間氏淑,看能不能有開源的實現(xiàn)。
再來就是在 Mac OS X 下面硕噩,panic 出來的堆棧完全沒法看假残,沒有 file 和 line number 的信息,根本沒法方便的查 bug。
當然辉懒,畢竟 Rust 是一門比較新的語言阳惹,還在不斷的完善發(fā)展,我們還是很有信心它能越來越好的眶俩。
Q & A
1. Go 的 Cgo 在效率上面與 Rust FFI 有啥區(qū)別莹汤?
唐劉:我自己寫過一個簡單的測試,就是都循環(huán)調(diào)用 Snappy 的 MaxCompressedLength 這個函數(shù) 10000 次颠印,發(fā)現(xiàn) Rust 的 FFI 比 Go 的 Cgo 要快上一個數(shù)量級纲岭,雖然這么測試不怎么精確,但至少證明了 Rust 的 FFI 性能更好线罕。
2. 在官方的介紹中止潮,Rust 的首選平臺是 Windows, 那是否可以生成 dll. 你們的 IDE 用的是什么?
唐劉:我沒用過 Windows钞楼,所以也不知道怎么生成 dll喇闸,開發(fā) Rust 的 ide 也就是常用的那幾個,譬如 Vim窿凤, Emacs仅偎, Sublime 這些,反正都有 Rust 的插件支持雳殊。
3. Rust 調(diào)用 C 的庫方便嗎橘沥?
唐劉:Rust 通過 FFI 調(diào)用 C,很方便的夯秃,這里有相關文檔 (https://doc.rust-lang.org/book/ffi.html)座咆,但畢竟這涉及到跨語言,代碼寫起來就不怎么好看了仓洼。而且 FFI 需要 unsafe保護介陶,所以通常我們會在外面在 wrap 一層 Rust 的函數(shù)。
4. Rust 性能指標如何色建?
唐劉:Rust 性能這個不怎么好衡量哺呜,因為我們只是在一些特定的環(huán)境下面做過跟 Go 的對比,譬如 Cgo vs FFI 的測試箕戳,這方面性能是比 Go 要好的某残。另外,Rust 是一門靜態(tài)語言陵吸,沒有 GC玻墅,所以我覺得他的性能不會是問題,不然 Dropbox 也不可能將類 S3 的應用用 Rust 寫了壮虫。
5. Rust 周邊生態(tài)如何? 如跟常用的 DBSQL/MQ 等第三方系統(tǒng)的 binding澳厢?
唐劉:Rust 的生態(tài)只能呵呵來形容了,跟 Go,Java 這些的沒法比剩拢。雖然有常用的 MySQL 等的 binding线得,但我沒用過。主要原因在于官方的網(wǎng)絡 IO 是同步的裸扶,所以必須借助多線程來進行這些處理框都,而用 MIO 這種異步模式,大家也知道寫出來的代碼邏輯切割很厲害呵晨。所以通常我們也不會拿 Rust 來做這些復雜的業(yè)務系統(tǒng)開發(fā)魏保,感覺還是 Go 更合適。
與C摸屠,C++不同谓罗,java規(guī)范中沒有“依賴具體實現(xiàn)”的地方,基本數(shù)據(jù)類型大小以及有關算法都做了明確的說明季二。例如檩咱,Java中int類型永遠為32位整數(shù),而C/C++中int的類型大小有可能是16位胯舷,32位刻蚯,也可能與編譯器的設置有關。在java中桑嘶,數(shù)據(jù)類型具有固定的大小炊汹,從而具有很好的可移植性。
本文轉(zhuǎn)載自 高可用架構公眾號「 ArchNotes 」文章
原文:《Rust語言入門逃顶、關鍵技術與實戰(zhàn)經(jīng)驗》
作者: 唐劉
鏈接:https://mp.weixin.qq.com/s/Wlz1G-eYgA9uEgO_63lK6Q
參考
(1)Rust 語言中文版-極客學院教程
http://wiki.jikexueyuan.com/project/rust/
(2)RUST官方網(wǎng)站
https://www.rust-lang.org/zh-CN/
https://www.rust-lang.org/zh-CN/learn
(3)標準文檔庫
https://doc.rust-lang.org/stable/std/index.html
補充
(1)GO和RUST的區(qū)別讨便?
- go定位是云計算時代的C語言,主要是面向云計算領域的以政。而rust是系統(tǒng)級語言霸褒,更Low level一些
- 都是強類型語言,go有GC(Garbage Collection,垃圾回收)而rust沒有盈蛮;
3)go目前沒有模板废菱,rust有,換言之抖誉,rust的編程范式更豐富一些 - go簡單殊轴,上手快,rust因為有變量的lifetime概念和內(nèi)存的borrow概念寸五,上手難一些梳凛;
5)安全性耿币。Rust語法引入所有權和生命期概念梳杏,在編譯期就能檢查出一部分內(nèi)存管理錯誤,這是rust的一個殺手锏的特性。