我們學會函式後,程式碼可以分離,然而,隨著專案規模上升,函式名稱有可能相互衝突。雖然,我們也可以修改函式名稱,但是,只靠函數名稱來區分函式,往往會造成函數名稱變得冗長。像 C 語言中,沒有額外的機制處理函式名稱的衝突,就會看到很多長名稱的函式,像是 gtk_application_get_windows
(出自 GTK+ 函式庫)。Rust 提供模組 (module) 的機制,處理函式命名衝突的問題。
註:在許多程式語言中,以命名空間 (namespace) 提供類似的機制。
在我們先前的內容中,函式和主程式都寫在同一個檔案。在實務上,我們會將函式或物件獨立出來,製成套件 (package),之後可以重覆利用。例如,同一套函式庫,可供終端機或圖形介面等不同使用者介面來使用。在 Rust 中,套件和模組相互關連。Rust 的套件又稱為 crate。
使用模組
雖然我們在先前的內容沒有強調模組,實際上,我們已經在使用模組了。我們回頭看先前的一個例子:
在這個例子中,我們呼叫 std
函式庫之中的 f64
模組,之後,就可以呼叫該模組內的 sqrt
函式。
撰寫模組
在 Rust 中,使用 mod
這個關鍵字來建立模組。如下例:
在本例中,我們在兩個模組中定義了同名而不同功能的函式。由於這兩個函式被區隔不同的模組中,不會有命名衝突的問題。模組除了區隔函式名稱外,也提供私有區塊,在模組中的函式或物件,需以 pub
關鍵字宣告,否則無法在模組外使用。
如同我們先前看到的範例,模組也可以內嵌。如下例:
由本例可知,透過模組的機制,可以協助我們整理函式。
建立套件
在我們先前的範例中,我們建立的是應用程式專案,如下:
但若想將函式或物件獨立出來,供其他 Rust 程式使用,則要用函式庫專案,如下:
我們現在實際建立一個函式庫套件。以上述指令建立 mylib 函式庫套件。加入以下函式:
之後,退回到上一層目錄,建立 myapp 主程式套件。加入以下內容:
透過 extern crate
可以呼叫外部專案。另外,要修改 Cargo.toml 紀錄檔,加入以下內容:
之後,執行該專案,若可正確執行,代表我們成功地建立套件。
如果函式庫存放在遠端站台上,需修改存取位置。在下例中,我們存取以 Git 存放的函式庫:
Cargo.toml 是 Rust 套件 (i.e. crate) 使用的設定檔。建議花一些時間熟悉其官方文件。
在套件中使用模組
在我們先前的例子中,透過 mylib 函式庫對函式命名做最基本的區隔。不過,我們也可以在函式庫中使用模組來進一步區隔函式。我們先以實例看加入模組後的效果:
同樣地,需於 Cargo.toml 加入套件位置:
我們現在要實際建立這個函式庫。退回上一層目錄,建立 phrase 函式庫專案:
整個 phrase 專案結構如下:
在 src/lib.rs 中宣告模組,記得要宣告公開權限:
在 src/english/mod.rs 中宣告子模組:
在 src/english/greeting.rs 中實作函式:
同樣地,在 src/chinese/mod.rs 中宣告子模組:
同樣地,在 src/chinese/greeting.rs 中實作函式:
由於 Rust 的模組及套件和檔案名稱是連動的,若使用錯誤的檔案名稱將無法編譯,需注意。
進階的模組使用方式
在先前的例子中,由於函式庫結構較複雜,使得函式呼叫的動作變得繁瑣,Rust 提供別名來簡化這個動作。如下例:
Rust 官方文件中提供了另一個更複雜的模組呼叫範例:
稍微閱讀一下程式碼,大概就知道如何呼叫模組。要注意的是,globbing 的動作,會直接暴露函式名稱到主程式中,喪失使用模組區隔函式名稱的用意,應盡量避免。