💂

Rustの名前解決の仕組み: Prelude

2023/01/15に公開約2,600字

Rustにはpreludeという名前解決の仕組みがある。これについて調べる。

The Rust Reference: Prelude

preludeとは

preludeとは、crate内の全てのmoduleのスコープに自動的に取り込まれる名前の集まり。名前解決に使われる。

例えば、Boxという名前は (#![no_std]がない限り) 全てのmoduleで使うことができる。それにもかかわらずself::Boxなど存在しない。これはBoxがmodule自体の持つ名前ではなく、preludeに存在する名前であるため。

5種類のprelude

preludeにはいくつか種類がある。

  • standard library prelude
  • extern prelude
  • language prelude
  • macro_use prelude
  • tool prelude

standard library prelude

全てのcrateはstandard library preludeを持つ。このstandard library preludeは1つのmoduleから成るが、そのmoduleはcrateのedition ("2015" or "2018" or "2021") と#![no_std]が適用されているかどうかによって異なる。

#![no_std]が適用されていない場合はstd::prelude::rust_<edition>、適用されている場合はcore::prelude::rust_<edition>がstandard library preludeとなる。

extern prelude

extern crateやコンパイラーの--externオプションでインポートされたcrateたちはextern preludeに追加される。(もしextern crate orig_name as new_nameとaliasでインポートされたらnew_nameの方が追加される。)

coreは常にextern preludeに追加される。#![no_std]がない限り、stdも追加される。

extern preludeを使った実験

extern preludeを使うとちょっとしたことができる。

2つのファイルを用意する。

// ./main.rs

fn main() {
    hi::say_hi();
}
// hi.rs

pub fn say_hi() {
    println!("Hi.");
}

hi.rsをrlibとしてコンパイルし (libhi.rlib)、main.rsをコンパイルする際にlibhi.rlibhi crateとしてextern preludeに追加する。

$ rustc --crate-type=rlib ./hi.rs
$ rustc --extern hi=$(pwd)/libhi.rlib main.rs
$ ./main
Hi.

std libraryなどではないものが、ビルトインみたいに使える。

language prelude

language preludeには、型 (bool, char, str, i32, ...) やattribute (cfg, derive, proc_macro, ...) の名前が含まれる。

macro_use prelude

macro_use preludeには、extern cratemacro_use attributeでインポートされた、外部crateのmacroが含まれる。

ここにstdからエクスポートされた全てのmacroが含まれる。#![no_std]の場合はstdではなくcoreとなる。

tool prelude

tool preludeには、#[rustfmt::skip]#[clippy::cyclomatic_complexity = "100"]といったtool attributesの名前が含まれる。

no_implicit_prelude attribute

crateまたはmoduelに#![no_implicit_prelude]を適用すると、standard library prelude、extern prelude、tool prelude、macro_use preludeを自動的にスコープに取り入れることがなくなる。(language preludeには影響なし。) これは子孫moduleにも適用される。

なお、#![no_std]との名前の一貫性を理由に#![no_implicit_prelude]#![no_prelude]にリネームして、さらに対象のmoduleのみに影響するようにする、というRFC: rust-lang/rfcs#501があるようだ。ただ、このRFCのtracking issueが2022年にcloseされた (能力とやる気のある人待ちのようだ。) ので進捗はないみたい。

参照

Discussion

ログインするとコメントできます