99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Rust 使用 use 關(guān)鍵字將路徑引入作用域

2023-03-22 15:09 更新
ch07-04-bringing-paths-into-scope-with-the-use-keyword.md
commit 2d605f66b3d891dea0a2f684ece508aa2282b854

到目前為止,似乎我們編寫的用于調(diào)用函數(shù)的路徑都很冗長且重復,并不方便。例如,示例 7-7 中,無論我們選擇 add_to_waitlist 函數(shù)的絕對路徑還是相對路徑,每次我們想要調(diào)用 add_to_waitlist 時,都必須指定front_of_house 和 hosting。幸運的是,有一種方法可以簡化這個過程。我們可以使用 use 關(guān)鍵字將路徑一次性引入作用域,然后調(diào)用該路徑中的項,就如同它們是本地項一樣。

在示例 7-11 中,我們將 crate::front_of_house::hosting 模塊引入了 eat_at_restaurant 函數(shù)的作用域,而我們只需要指定 hosting::add_to_waitlist 即可在 eat_at_restaurant 中調(diào)用 add_to_waitlist 函數(shù)。

文件名: 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();
}

示例 7-11: 使用 ?use ?將模塊引入作用域

在作用域中增加 use 和路徑類似于在文件系統(tǒng)中創(chuàng)建軟連接(符號連接,symbolic link)。通過在 crate 根增加 use crate::front_of_house::hosting,現(xiàn)在 hosting 在作用域中就是有效的名稱了,如同 hosting 模塊被定義于 crate 根一樣。通過 use 引入作用域的路徑也會檢查私有性,同其它路徑一樣。

你還可以使用 use 和相對路徑來將一個項引入作用域。示例 7-12 展示了如何指定相對路徑來取得與示例 7-11 中一樣的行為。

文件名: 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();
}

示例 7-12: 使用 ?use ?和相對路徑將模塊引入作用域

創(chuàng)建慣用的 use 路徑

在示例 7-11 中,你可能會比較疑惑,為什么我們是指定 use crate::front_of_house::hosting ,然后在 eat_at_restaurant 中調(diào)用 hosting::add_to_waitlist ,而不是通過指定一直到 add_to_waitlist 函數(shù)的 use 路徑來得到相同的結(jié)果,如示例 7-13 所示。

文件名: src/lib.rs

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();
}

示例 7-13: 使用 ?use ?將 ?add_to_waitlist ?函數(shù)引入作用域,這并不符合習慣

雖然示例 7-11 和 7-13 都完成了相同的任務(wù),但示例 7-11 是使用 use 將函數(shù)引入作用域的習慣用法。要想使用 use 將函數(shù)的父模塊引入作用域,我們必須在調(diào)用函數(shù)時指定父模塊,這樣可以清晰地表明函數(shù)不是在本地定義的,同時使完整路徑的重復度最小化。示例 7-13 中的代碼不清楚 add_to_waitlist 是在哪里被定義的。

另一方面,使用 use 引入結(jié)構(gòu)體、枚舉和其他項時,習慣是指定它們的完整路徑。示例 7-14 展示了將 HashMap 結(jié)構(gòu)體引入二進制 crate 作用域的習慣用法。

文件名: src/main.rs

use std::collections::HashMap;

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

示例 7-14: 將 ?HashMap ?引入作用域的習慣用法

這種習慣用法背后沒有什么硬性要求:它只是一種慣例,人們已經(jīng)習慣了以這種方式閱讀和編寫 Rust 代碼。

這個習慣用法有一個例外,那就是我們想使用 use 語句將兩個具有相同名稱的項帶入作用域,因為 Rust 不允許這樣做。示例 7-15 展示了如何將兩個具有相同名稱但不同父模塊的 Result 類型引入作用域,以及如何引用它們。

文件名: src/lib.rs

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

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

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

示例 7-15: 使用父模塊將兩個具有相同名稱的類型引入同一作用域

如你所見,使用父模塊可以區(qū)分這兩個 Result 類型。如果我們是指定 use std::fmt::Result 和 use std::io::Result,我們將在同一作用域擁有了兩個 Result 類型,當我們使用 Result 時,Rust 則不知道我們要用的是哪個。

使用 as 關(guān)鍵字提供新的名稱

使用 use 將兩個同名類型引入同一作用域這個問題還有另一個解決辦法:在這個類型的路徑后面,我們使用 as 指定一個新的本地名稱或者別名。示例 7-16 展示了另一個編寫示例 7-15 中代碼的方法,通過 as 重命名其中一個 Result 類型。

文件名: src/lib.rs

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

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

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

示例 7-16: 使用 ?as? 關(guān)鍵字重命名引入作用域的類型

在第二個 use 語句中,我們選擇 IoResult 作為 std::io::Result 的新名稱,它與從 std::fmt 引入作用域的 Result 并不沖突。示例 7-15 和示例 7-16 都是慣用的,如何選擇都取決于你!

使用 pub use 重導出名稱

使用 use 關(guān)鍵字,將某個名稱導入當前作用域后,這個名稱在此作用域中就可以使用了,但它對此作用域之外還是私有的。如果想讓其他人調(diào)用我們的代碼時,也能夠正常使用這個名稱,就好像它本來就在當前作用域一樣,那我們可以將 pub 和 use 合起來使用。這種技術(shù)被稱為 “重導出re-exporting)”:我們不僅將一個名稱導入了當前作用域,還允許別人把它導入他們自己的作用域。

示例 7-17 將示例 7-11 根模塊中的 use 改為 pub use 。

文件名: src/lib.rs

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();
}

示例 7-17: 通過 pub use 使名稱可從新作用域中被導入至任何代碼

通過 pub use重導出,外部代碼現(xiàn)在可以通過新路徑 restaurant::hosting::add_to_waitlist 來調(diào)用 add_to_waitlist 函數(shù)。如果沒有指定 pub use,外部代碼需在其作用域中調(diào)用 restaurant::front_of_house::hosting::add_to_waitlist。

當你代碼的內(nèi)部結(jié)構(gòu)與調(diào)用你代碼的程序員所想象的結(jié)構(gòu)不同時,重導出會很有用。例如,在這個餐館的比喻中,經(jīng)營餐館的人會想到“前臺”和“后臺”。但顧客在光顧一家餐館時,可能不會以這些術(shù)語來考慮餐館的各個部分。使用 pub use,我們可以使用一種結(jié)構(gòu)編寫代碼,卻將不同的結(jié)構(gòu)形式暴露出來。這樣做使我們的庫井井有條,也使開發(fā)這個庫的程序員和調(diào)用這個庫的程序員都更加方便。

使用外部包

在第二章中我們編寫了一個猜猜看游戲。那個項目使用了一個外部包,rand,來生成隨機數(shù)。為了在項目中使用 rand,在 Cargo.toml 中加入了如下行:

文件名: Cargo.toml

rand = "0.8.3"

在 Cargo.toml 中加入 rand 依賴告訴了 Cargo 要從 crates.io 下載 rand 和其依賴,并使其可在項目代碼中使用。

接著,為了將 rand 定義引入項目包的作用域,我們加入一行 use 起始的包名,它以 rand 包名開頭并列出了需要引入作用域的項?;貞浺幌碌诙碌?“生成一個隨機數(shù)” 部分,我們曾將 Rng trait 引入作用域并調(diào)用了 rand::thread_rng 函數(shù):

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
}

crates.io 上有很多 Rust 社區(qū)成員發(fā)布的包,將其引入你自己的項目都需要一道相同的步驟:在 Cargo.toml 列出它們并通過 use 將其中定義的項引入項目包的作用域中。

注意標準庫(std)對于你的包來說也是外部 crate。因為標準庫隨 Rust 語言一同分發(fā),無需修改 Cargo.toml 來引入 std,不過需要通過 use 將標準庫中定義的項引入項目包的作用域中來引用它們,比如我們使用的 HashMap

use std::collections::HashMap;

這是一個以標準庫 crate 名 std 開頭的絕對路徑。

嵌套路徑來消除大量的 use 行

當需要引入很多定義于相同包或相同模塊的項時,為每一項單獨列出一行會占用源碼很大的空間。例如猜猜看章節(jié)示例 2-4 中有兩行 use 語句都從 std 引入項到作用域:

文件名: src/main.rs

// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--

相反,我們可以使用嵌套路徑將相同的項在一行中引入作用域。這么做需要指定路徑的相同部分,接著是兩個冒號,接著是大括號中的各自不同的路徑部分,如示例 7-18 所示。

文件名: src/main.rs

// --snip--
use std::{cmp::Ordering, io};
// --snip--

示例 7-18: 指定嵌套的路徑在一行中將多個帶有相同前綴的項引入作用域

在較大的程序中,使用嵌套路徑從相同包或模塊中引入很多項,可以顯著減少所需的獨立 use 語句的數(shù)量!

我們可以在路徑的任何層級使用嵌套路徑,這在組合兩個共享子路徑的 use 語句時非常有用。例如,示例 7-19 中展示了兩個 use 語句:一個將 std::io 引入作用域,另一個將 std::io::Write 引入作用域:

文件名: src/lib.rs

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

示例 7-19: 通過兩行 ?use ?語句引入兩個路徑,其中一個是另一個的子路徑

兩個路徑的相同部分是 std::io,這正是第一個路徑。為了在一行 use 語句中引入這兩個路徑,可以在嵌套路徑中使用 self,如示例 7-20 所示。

文件名: src/lib.rs

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

示例 7-20: 將示例 7-19 中部分重復的路徑合并為一個 ?use ?語句

這一行便將 std::io 和 std::io::Write 同時引入作用域。

通過 glob 運算符將所有的公有定義引入作用域

如果希望將一個路徑下 所有 公有項引入作用域,可以指定路徑后跟 *,glob 運算符:

use std::collections::*;

這個 use 語句將 std::collections 中定義的所有公有項引入當前作用域。使用 glob 運算符時請多加小心!Glob 會使得我們難以推導作用域中有什么名稱和它們是在何處定義的。

glob 運算符經(jīng)常用于測試模塊 tests 中,這時會將所有內(nèi)容引入作用域;我們將在第十一章 “如何編寫測試” 部分講解。glob 運算符有時也用于 prelude 模式;查看 標準庫中的文檔 了解這個模式的更多細節(jié)。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號