言語アイテム
コンパイラには、いくつかのプラグ可能な操作があります。つまり、言語にハードコードされているのではなく、ライブラリで実装され、コンパイラにそれが存在することを伝える特別なマーカーを持つ機能です。そのマーカーは属性 #[lang = "..."] であり、... にはさまざまな値、すなわちさまざまな「言語アイテム」があります。
このような言語アイテムの多くは、add(trait core::ops::Add)や future_trait(trait core::future::Future)のように、妥当な実装方法が 1 つしかありません。一方で、特定の目的を達成するためにオーバーライドできるものもあります。たとえば、バイナリのエントリポイントを制御できます。
言語アイテムによって提供される機能には、次のものがあります。
- トレイトによるオーバーロード可能な演算子:
==、<、参照外し(*)、+などの演算子に対応するトレイトはすべて言語アイテムでマークされています。これら特定の 4 つは、それぞれeq、ord、deref、addです。 - パニックとスタックアンワインディング:
eh_personality、panic、panic_bounds_checks言語アイテム。 - コンパイラが使用する型の性質を示すために使われる
std::markerのトレイト: 言語アイテムsend、sync、copy。 core::markerにある分散性インジケーターに使われる特殊なマーカー型: 言語アイテムphantom_data。
言語アイテムはコンパイラによって遅延ロードされます。たとえば、Box をまったく使わないのであれば、exchange_malloc や box_free の関数を定義する必要はありません。あるアイテムが必要になったものの、現在のクレートやそれが依存するいずれのクレートにも見つからない場合、rustc はエラーを出力します。
ほとんどの言語アイテムは core ライブラリによって定義されていますが、#![no_std] で実行可能ファイルをビルドしようとしている場合は、通常 std によって提供されるいくつかの言語アイテムを定義する必要があります。
言語アイテムの取得
tcx.lang_items() を呼び出すことで言語アイテムを取得できます。
以下は、trait Sized {} 言語アイテムを取得する小さな例です。
#![allow(unused)]
fn main() {
// `#![no_core]` の場合、このトレイトは利用できないことに注意してください。
if let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() {
// `sized_trait_def_id` で何かを行う
}
}
sized_trait() は DefId そのものではなく、Option を返すことに注意してください。
これは、言語アイテムが標準ライブラリで定義されているため、誰かが #でコンパイルすると、その言語アイテムが存在しない可能性があるからです。
次のいずれかを行えます。
- 続行するためにその言語アイテムが必要な場合は、ハードエラーを出す(これはユーザーコードで発生する可能性があるため、パニックしないでください)。
DefIdを使って行おうとしていた処理を単に省くことで、限定された機能で処理を続行する。
すべての言語アイテムの一覧
言語アイテムは次の場所で見つけることができます。
- コンパイラドキュメント内の網羅的なリファレンス:
rustc_hir::LangItem - ripgrep を使用した、ソース位置付きの自動生成リスト:
rg '#\[.*lang =' library/
言語アイテムは明示的に不安定であり、新しいリリースで変更される可能性があることに注意してください。