iT邦幫忙

2023 iThome 鐵人賽

DAY 20
1
AI & Data

Rust 加 MLOps,你說有沒有搞頭?系列 第 20

[Day 20] - 中場休息 🏖️ 如何度過 Rust 新手村? 我要打十個 Borrow checker!

  • 分享至 

  • xImage
  •  

今日份 Ferris

今天要來打 Boss!畫出來的圖很酷,搭配 Ferris 屁屁好魔性 🥹
https://ithelp.ithome.com.tw/upload/images/20231005/20141304W6tVHgLp60.jpg
*Ferris from strager - Faster than Rust and C++: the PERFECT hash table

Rust 新手村

談到 Rust,很多人第一印象就是很難。
在一開始學習時,我也曾茫然地盯著範例卻完全不知道每個部分到底在做什麼,甚至連問問題都不知道該怎麼問。
但在 Rust 社群中問了許多很傻瓜的問題之後,我發現許多大神的回答都蘊含了一個概念:

Rust 並不是很難,而是不熟悉。

偏偏這個不熟悉就是最讓人挫折的,但只要熬過一開始的階段,了解 Rust 慣用的寫法,很多本來完全看不懂的原始碼就會漸漸的變得有道理。

而經過這一個多月的探索,我認為學習 Rust 就像是身處於一個充滿挑戰的冒險世界,這個世界的新手村就是最開始不熟悉的學習階段。

這個新手村充滿了各種神奇的技能和道具,但也有一個強大的魔王守護著最終的寶藏,這位魔王就是 borrow checker,這位魔王是 Rust 的核心守護者,負責確保這個冒險世界中的記憶體安全。

在新手村的早期,我們會學到一些基本的技能,比如如何宣告變數、定義函數和進行基本的數據操作。
這些技能就像是你在冒險世界中的基本武器和裝備,讓你能夠應對一些簡單的挑戰,比如擊敗一些小怪物或解開門鎖。

然而,當我們開始進一步探索這個世界,進入到更複雜的任務和挑戰時,就會遇到魔王 borrow checker。

這位魔王非常嚴格,他要求我們在使用變數和資源時,時刻保持精確和安全。
這就像是在新手村的某個地方,我們必須解開一個複雜的迷宮,但每一步都必須小心翼翼,否則就會被迷宮的陷阱擊敗。

魔王 borrow checker 會檢查我們的程式碼,確保你不會遇到潛在的資源競爭、空指針或其他危險情況。
這雖然使學習 Rust 變得更有挑戰性,但也確保了我們的程式碼在執行時非常穩定和可靠。

學習 Rust 就像是在一個冒險世界中不斷挑戰自己,在習得新技能的同時要小心應對魔王 borrow checker。

這條路可能有一些困難,但最終我們將獲得一個強大的武器 —— 能夠編寫高性能和安全程式碼的技能。

正如 Rust 教學型 Youtuber No Boilerplate 所說:

In other languages simple things are easy and complex things are possible, in Rust simple things are possible and complex things are EASY!

Rust 新手大禮包

https://ithelp.ithome.com.tw/upload/images/20231005/20141304nyLpe2jr1T.jpg

當進入 Rust 新手村時,會發現還沒輸入禮包碼官方就送了三件神裝:
https://ithelp.ithome.com.tw/upload/images/20231004/20141304Vs9EmPISs2.png

這些資源將幫助我們成功度過這個新手村冒險:

  • 《The Rust Programming Language》(通常被稱為 "The Book")
    這本書是我們的基礎裝備,它提供了深入且清晰的指南,幫助我們了解 Rust 的基本概念和語法。
    就像是一張地圖,指引我們穿越新手村的各個地區,從基本的變數和函數開始,逐步引導我們通過所有主要的概念,如所有權、借用和生命周期。
    這本書提供的範例和練習將幫助我們建立起強大的基礎,使我們能夠應對更具挑戰性的任務。
  • Rustlings
    Rustlings 就像是主線任務,讓我們可以在新手村裡面賺經驗跟資源。
    它提供了一組與 The book 相輔相成的練習,讓我們實際應用 The Book 中學到的知識。
    而每個練習都像是一個小任務,讓我們進一步磨練技能。
    就像在解新手任務一樣,隨著完成的任務增加,我們可以解鎖新的技巧和理解更多 Rust 的細節。
  • 《Rust By Example》
    這本書就像是我們的技能升級書,它提供了更多的範例和實用情境,讓我們更深入地理解如何應用 Rust。
    這些範例會幫助我們更深入地理解如何使用 pattern matching、trait、Macro 等高級特性。
    就像是在新手村中練習各種技能,以應對更強大的敵人。

總的來說,The book 提供我們理論知識,Rustlings 提供了實踐經驗,而 Rust By Example 則提供了更多高級技能。
藉由結合這些資源,我們就能夠在 Rust 的新手村中掌握強大的能力,並迎接更多挑戰。

新手攻略

在進入 Rust 的新手村後,你可能會感到有點迷茫,不知道該如何使用大禮包。
不用擔心,以下是一些建議的服用方法:

  1. 快速看完 The Rust Programming Language:
    剛進入新手村,我們不會馬上投入戰鬥,而是快速掃視整個地區的地圖。
    這是我們的探索階段,不必與每個怪物戰鬥,只需了解這個地方的環境和主要地標。
    這就像是快速閱讀 The Rust Programming Language,瞭解 Rust 的核心概念,但不要害怕,把疑問記在心裡,我們將在後面的遊戲中回來處理。

  2. 使用 The Rust Programming Language 布朗大學版:
    一旦完成了探索階段,我們就可以在這個新手村中展開冒險。
    這個版本提供了更多習題與圖解 (還可以用螢光筆畫重點🖌️),這部分可以按照正常步調閱讀,並跟著實際操作。
    建議在閱讀完第三章後,搭配下一步的活動進型。

  3. 安裝 Rustlings:
    Rustlings 就像是一個訓練場,我們可以在其中挑戰各種難度的 Rust 任務。這是磨練 Rust 技能的好地方,從簡單到困難,逐步提高難度。
    就像彈吉他需要練習爬格子一樣,Rustlings 可以訓練大腦建立 "肌肉記憶",使我們能夠更流暢地撰寫 Rust 程式碼。
    建議每週花一些時間重複做 Rustlings,以保持技能的鋒利度。

  4. 學習 Haskell:
    最後,這一點可能有點莫名其妙,但學習一些 Functional Programming 的概念,實際上可以幫助我們寫出更優秀的 Rust 程式碼。
    例如在 Iron LLaMa 專案中就出現了 conversation.get().messages.iter().map(...) 的用法。
    這是如何應用抽象思維和函數式編程原則於 Rust 的一個有趣方法,並使我們能夠更好地理解 Rust 中的一些特性。這就像是在新手村中學習額外技能,以應對更具挑戰性的敵人。
    但也不是要專精另一個語言,只需要快速讀過 Learn You a Haskell 有個基本概念就好!

上面的小攻略將有助於我們充分利用 Rust 新手大禮包,確保我們在新手村打下堅固的基礎,為未來的冒險做好充分的準備。
不管是在研究核心概念,挑戰 Rustlings,還是學習 Haskell,這些方法都將讓我們更強大,能夠應對魔王 borrow checker 和其他挑戰。

編譯器

從 Python 的背景來說,除了概念上的困難,語法也是一個大挑戰,很多時候在 Python 中很簡單的寫法到 Rust 就變得比較複雜,以建立一個 DataFrame 為例:
https://ithelp.ithome.com.tw/upload/images/20231004/201413042wkF1EnQkr.png

但當我們決定踏入 Rust 的新手村冒險時,其實並不孤單。
很快我們就會發現有一個非常重要的小幫手 — 編譯器,它總是站在我們身邊,幫助我們面對挑戰。

編譯器小幫手會不斷檢查我們的行動,當我們在新手村中寫下一段 Rust 程式碼時,小幫手就會迅速掃視它,確保它遵循了 Rust 的規則和法則。

有時,我們可能會犯一些錯誤,就像是在新手村中踩入陷阱或遇到怪物。
當這些錯誤發生時,編譯器小幫手會不厭其煩地告訴我們,指出問題的所在,就像是一位警告我們危險的朋友,總是確保你不會受傷或陷入困境。

然而,這位小幫手不僅僅是一個守護者,它也是一位導師。
當我們理解並修復了錯誤,它會給予你一個讚賞,就像是在遊戲中完成一個任務,獲得經驗值一樣。
如此一來,我們的技能將不斷提升,也能更有自信地繼續冒險!

Borrow checker

本來在規劃這個系列文時想要花個幾天 (啊~想想 borrow checker 的海量迷因🥰) 談談所有權、生命週期等 Rust 最讓人卻步的特色,但時間所剩不多,這裡就把準備好的內容濃縮成小秘笈讓讀者帶在身上吧!
https://ithelp.ithome.com.tw/upload/images/20231005/20141304r9O1cvbGBW.jpg

當我們準備好挑戰 Borrow Checker 並探索 Rust 的冒險世界時,首先需要更多的知識!

在這個冒險世界中,有兩個關鍵的地點:Stack 和 Heap,它們是我們在這個世界中儲存資料的地方,每個都有自己的規則。

  • Stack 就像是一個小而快速的儲物櫃,用於儲存變數和資料的固定大小部分。
    當我們宣告一個變數,這個變數通常會被存放在 Stack 中。
    Stack 的規則是簡單而嚴格的,每個變數的大小必須在編譯時就確定,而存放在 Stack 中的資料必須有固定的生命週期。
  • Heap 則像是一個巨大的倉庫,用於存放大小不確定或需要在執行時分配的資料。
    需要一個動態分配的資料時,例如一個可變大小的字串或一個結構體,這些資料通常會被存放在 Heap 中。
    Heap 的規則相對鬆散,資料可以有不同的生命週期,但必須由所有者負責回收。

Stack 和 Heap 是我們在這個冒險中的關鍵參考點,我們必須了解資料是存放在哪裡,以及如何有效地管理它們。

但要在這個冒險世界中安穩的前進,我們還需要一個強大的秘笈,叫做「所有權」。

所有權是 Rust 最獨特的特點之一,它讓這個世界免於垃圾回收的困擾,同時確保了記憶體的安全。
要想打敗 Borrow Checker,我們必須精通這個秘笈中的規則。

這個秘笈的核心原則是,當你擁有資料時,你就負責管理它

它有一些關鍵的參考規則,包括:

  • 在任何時候,你要麼只能擁有一個可變參考 (Mutable Reference),要麼可以擁有任意數量的不可變參考(Immutable Reference)。
  • 所有參考必須永遠有效,不能出現迷途參考,也就是參考的資料在被使用前就被刪除,從而使參考無法找到原始資料。

這就是「Pointer Safety Principle」,資料不可以同時被多個寫入者 (Mutable Reference) 和多個讀者(Immutable Reference) 引用。

資料只能有一個寫入者或多個讀者,但不能同時兼而有之。

Borrow Checker 就是負責確保這些規則的執行,以防止並行程式中常見的錯誤之一 — 資料競爭 (Data Races)。

而所有權的概念通常在遇到 Heap 數據時更加重要,Heap 數據必須由正好一個變數擁有,Rust 會在所有者離開作用域時回收 Heap 數據。
但所有權可以轉移 (move),當我們賦值或呼叫函數時,它可以轉移到其他所有者。
重要的是,Heap 數據只能透過當前所有者訪問,不能透過之前的所有者訪問。

帶著這本秘笈不僅能自動釋放記憶體,還避免了重複釋放記憶體的問題。
當我們掌握了這個秘笈,就能夠在這個冒險世界中自如地操縱資源,並打敗 Borrow Checker,進一步探索 Rust 的奇妙之處。
所以,抓好大禮包,帶上這個秘笈,準備好挑戰新的冒險吧!

換個比喻,當我們使用 &var 時,就像是說你正在看電視,其他人可以一起觀看,但你不希望有人在你看電視時突然把電視關掉或轉台,這就是不可變參考。
然而,當我們使用 &mut var 時,就像是說你想換台節目,你手上有遙控器,這時誰都不能動,也不許看電視,這就是可變參考。

另外,真的很推薦 The Rust Programming Language 布朗大學版,它提供了很多像下面這樣的互動小圖來幫助我們理解:
https://ithelp.ithome.com.tw/upload/images/20231005/20141304U1r6xsq395.png
而且還有 Ownership Inventory 系列小習題可以考驗我們的理解程度!

好啦,今天就這樣,今天用了遊戲做比喻,所以最後也用遊戲結尾吧,來玩玩 抓螃蟹 放鬆一下:
crab-tag
明天見啦~
/images/emoticon/emoticon24.gif


上一篇
[Day 19] - 鋼鐵草泥馬 🦙 LLM chatbot 🤖 (10/10)|結論及展望
下一篇
[Day 21] - 機器學習系統設計 🏭 x Rust 🦀
系列文
Rust 加 MLOps,你說有沒有搞頭?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
marvinhsu
iT邦新手 4 級 ‧ 2023-10-16 09:55:01

其實我覺得rust跟OCaml有很多很像的地方

我要留言

立即登入留言