iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 30
1
自我挑戰組

WebAssembly + Rust 的前端應用系列 第 30

[Day 30] Rust Use (實作 Actix 後的說明以及補充 PART5)

各位好~雖然今天是挑戰的最後一天但是筆者還是會把這個系列介紹完,下面是目前的進度。

Struct

  • Managing Growing Projects with Packages, Crates, and Modules
    • Packages and Crates
    • Modules
    • Paths
  • Storing Lists of Values with Vectors
  • Advanced Types
  • Macros

另外是今天有讀者問我還會不會繼續寫 wasm ,雖然那是我當初訂的題目沒錯但是後來幾乎都在寫 Rust (慚愧)剛開始的時候想得太美好以為時間很充裕沒想到轉眼已經 30 天了 XD。

雖然這次挑戰 wasm 寫得很少但是我之後會找個地方繼續寫 wasm 相關的文章,有興趣的同學可以先繼續關注這邊。

以下正文開始


Bringing Paths into Scope with the use Keyword

還記得上一篇我們當我們需要呼叫函式時的寫法嗎?

pub fn eat_at_restaurant() {
    // Absolute path
    crate::front_of_house::hosting::add_to_waitlist();

    // Relative path
    front_of_house::hosting::add_to_waitlist();
}

不管是用絕對路徑或是相對路徑都必須寫的很長一串,所幸 Rust 提供 use 的方法來引入物件至當前的 scope 例如下面這隻程式就把 hosting 的 module 給全部引入至 scope 裡面

src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}

由這支程式可以看到當我們 use hosting 之後 eat_at_restaurant 就可以使用 hosting 了。

至於若是 use 的路徑要使用相對路徑則比較特別我們必須在前面加上 self,例如下面的範例,

src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use self::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}

不過根據官網的說明這樣的寫法似乎只是暫時的 Rust 團隊說未來會把它消除掉,所以就請各位隨時注意更新的情況囉。

Creating Idiomatic use Paths

接著來討論一下慣用的用法,通常在 use 的時候我們不會這樣寫,

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting::add_to_waitlist;

pub fn eat_at_restaurant() {
    add_to_waitlist();
    add_to_waitlist();
    add_to_waitlist();
}

這樣我們通常會搞不清楚到底 add_to_waitlist 是不是屬於這個 scope 的函式若是我們保留他的父層 hosting 就像我們在上一個例子做的一樣,在判讀程式碼的時候會更直覺的知道他是來至不同 scope 的程式,因此要維持良好的寫程式習慣的話請不要這樣做囉。

不過若是在 use 像是 structsenums 等其他物件的時候我們通常就會使用完整的路徑,例如

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
}

這個例子直接指定路徑到 HashMap 並且調用。

不過官網也說了這邊倒是沒有什麼特別的理由就純粹是慣例方便閱讀,不過有時候還是會有例外,舉例來說當你有兩個同樣名稱的物件的時候,

use std::fmt;
use std::io;

fn function1() -> fmt::Result {
    // --snip--
}

fn function2() -> io::Result<()> {
    // --snip--
}

像是這邊就必須得用父層來區分。

Note: 慣例就只是建議並不代表你一定要照著做,若是團隊有共識要用什麼風格撰寫沒人管你。

Providing New Names with the as Keyword

使用 as 賦予一個新的名稱,這邊相信有寫過其他語言的大概都不陌生所以我們直接來看例子,

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    // --snip--
}

fn function2() -> IoResult<()> {
    // --snip--
}

這邊可以看到我們用 as 把 Result 重新命名成 IoResult,這樣就可以避免重複名稱的問題囉。

Re-exporting Names with pub use

pubuse 重新輸出物件,這邊其實也就是可以更加偷懶的先把想要 public 的路徑先寫好其他程式在 use 時就不用再寫很長一串,例如下面的寫法。

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}

這樣就等於把 hosting 給直接 public 出去了。

而這樣寫的好處是可以把 pubuse 的路徑結構分開例如當 hosting 在這支程式的路徑變了我只要透過修改 pub use 後面的路徑即可這樣其他有用到 hosting 的程式都不會被影響,很好的分離了實作跟 api 介面。

Using External Packages

通常當我們新增依賴也就是 crate 的時候該 package 的名字就是我們用來 use 的根目錄,還記得很久以前我們用過的 rand 嗎?

Cargo.toml

[dependencies]
rand = "0.5.5"

只要引入之後我們就可以在任何 scope 裡面取用到,

use rand::Rng;
fn main() {
    let secret_number = rand::thread_rng().gen_range(1, 101);
}

同樣的 Rust 裡面也有內建一些 package 像是 std

use std::collections::HashMap;

而因為是內建的所以我們不必把他加進依賴就可以直接使用。

Using Nested Paths to Clean Up Large use Lists

另外就是當我們需要從同個 module 或是 package 取用多個物件的時候我們可以用 {} 的方式拿到我們需要的,例如這支程式

use std::io;
use std::cmp::Ordering;

我們可以改寫成這樣,

use std::{cmp::Ordering, io};

這樣我們就可以減少很多行的 use 並且讓程式更好讀。

我們可以用這樣的方式整理任何在同個路徑下的檔案,例如這支程式

use std::io;
use std::io::Write;

可以改寫成這樣,

use std::io::{self, Write};

The Glob Operator

最後若是非常懶用到的物件很多我們可以直接用 * 把他們全部引入,例如這支程式

use std::collections::*;

這樣就等於把 collections 下面全部的物件都引入這個 scope 裡面了。

不過官網說不建議這樣做原因是這樣開發者就不知道到底有用到哪些物件了,通常會這樣做是在寫測試的時候,如果未來有機會的話再介紹,有興趣的可以先自己看看 How to Write Tests

結論

透過這幾篇所教的 module、path 和 use 我們就可以把程式碼拆開來放在各個不同的檔案下面,這邊我就不多做介紹了留給讀者自己去試試看吧!

那麼今天就結束了,我們明天見!

最後一樣有問題歡迎發問

/images/emoticon/emoticon07.gif

參考網址

ch07-04-bringing-paths-into-scope-with-the-use-keyword


上一篇
[Day 29] Rust Modules (實作 Actix 後的說明以及補充 PART4)
系列文
WebAssembly + Rust 的前端應用30

1 則留言

0
阿展展展
iT邦好手 1 級 ‧ 2020-01-31 05:37:55

恭喜完賽

我要留言

立即登入留言