Scrappy

覚え書き。

Rust:Bringing Paths into Scope with the use Keyword

Bringing Paths Into Scope with the use Keyword - The Rust Programming Language

関数を呼び出す時にpathを全部書くのは不便だと感じるかもしれない。 useキーワードでpathへのショートカットを作成できる。

crate rootに、use crate::front_of_house::hosting;を追加した場合、そのスコープ内でhostingが有効になる。 useuseが記述されたスコープでのみ有効になるため、以下はエラーとなる。

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

use crate::front_of_house::hosting;

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

問題を解決するには、usecustomerの中に移動させるか、super::hostingで親モジュールから参照させる。

慣用的なuseの使い方

useで関数をスコープに持ち込む場合は、関数名まで持ち込むのではなく親モジュールを持ち込む。 こうすることでその関数がどのモジュールで定義されているかが明確になる。

一方、構造体、enum、その他のitemを持ち込む場合は、フルパスを指定する。

use std::collections::HashMap;

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

このidiomに強い理由があるわけではないが、Rustのコードはこの形で読み書きされることに慣れている。 また、例外は同じ名前の2つのitemをスコープに持ち込む場合である。以下は異なる親モジュールを持つが、同じ名前のResult型をスコープに持ち込む方法である。

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

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

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

asキーワードで新しい名前を与える

同じ名前の2つの型をスコープに持ち込む別の方法として、asキーワードで新しいローカル名をつけることができる。

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

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

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

pub useによる名前の再公開

useーワードで名前をスコープに持ち込むと、その名前は新しいスコープ内で非公開(プライベート)になる。pubuseを組み合わせることで、その名前をあたかもそのコード内で定義されたかのように参照できるようにすることができる。この手法は「再公開(re-exporting)」と呼ばれる。

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

pub useにする前にadd_to_waitlist()呼び出すには、外部コードはrestaurant::front_of_house::hosting::add_to_waitlist()と指定する必要があり、またfront_of_houseをpublicにする必要があった。pub useを使うことで、hostingモジュールが再公開されたため、restaurant::hosting::add_to_waitlist()で使用が可能になる。

外部パッケージの利用

randパッケージを使用する際、Cargo.tomlに rand = "0.8.5"を追加した。 Cargoはcrates.ioからrandパッケージとその依存関係をダウンロードし、我々のプロジェクトで使用できるようにする。

その後、randの定義をプロジェクトのスコープに取り込むために、以下のように use 文を追加する。ここでは、クレート名 rand を先頭に指定し、スコープに取り込みたいアイテムを列挙する。Rngトレイトをスコープに取り込み、rand::thread_rng 関数を呼び出す。

use rand::Rng;

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

標準ライブラリstdも我々のパッケージから見ると外部クレートの1つである。ただ、Rust言語に付属しているため、Cargo.tomlにstdを記載する必要はない。しかし、itemをスコープに取り込む場合は、useが必要になる。

use std::collections::HashMap;

ネストしたpathで巨大なuseリストを整理する

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

以下のように書き換えることができる。

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

ネストしたpathは、pathのどのレベルでも使用できる。

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

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

glob演算子

use std::collections::*;

glob演算子を使うと、どの名前がスコープ内にあり、プログラムで使用される名前がどこで定義されたのかが分かりづらくなるため、注意が必要である。