読者です 読者をやめる 読者になる 読者になる

Rustの名前解決(1/4) 名前解決にかかわる構文

概要: Rustの名前解決の詳細について解説する。本記事では、名前解決に関する構文を紹介する。 Rustのモジュール Rustのコンパイルはcrate単位で行われ、必ずcrateのトップレベルモジュールに相当するファイルが存在する。これには lib.rs や main.rs という…

Rustのthread local gensym/internパターン

概要: Rustでgensymおよびinternを行う方法を説明する。 gensymとinternとは何か gensymパターンは、「まだ使われていない整数」を返す fresh() 関数を実装するというパターンである。型推論などで一時変数を作成するなどの用途で用いられる。 internパター…

Rustマクロの衛生性はどのように実現されているか(2/2) 構文の優先度に関する衛生性

概要: Rustマクロは2つの意味で衛生的である。その衛生性の説明とともに、それを実現するためのコンパイラの仕組みを説明する。 Rustマクロの2つの衛生性 Rustマクロ (ja) は次の2つの意味で衛生的(hygienic; 健全ともいう)である。 マクロ内で導入される変…

Rustマクロの衛生性はどのように実現されているか(1/2) 識別子に関する衛生性

概要: Rustマクロは2つの意味で衛生的である。その衛生性の説明とともに、それを実現するためのコンパイラの仕組みを説明する。 Rustマクロの2つの衛生性 Rustマクロ (ja) は次の2つの意味で衛生的(hygienic; 健全ともいう)である。 マクロ内で導入される変…

Rustは構文解析をしてからマクロを展開する

C言語では字句解析の次が前処理で、前処理のあとに構文解析が行われるが、Rustでは構文解析が終わってからマクロが展開される。 より正確に説明すると、Rustのコンパイルはcrate単位で行われ、crateのコンパイル処理の冒頭部は以下の2フェーズに分かれている…

Rustのself引数まとめ

概要: Rustの随所でself引数は特別扱いされている。それらの挙動について調べた。 self引数とメソッド Rustではnon-staticメソッドは self という特殊な名前の引数を持つ関数として定義されている。例えば、 struct A; // parse_self_arg impl A { fn f1(sel…

Rustトレイトの既定実装と否定実装

概要: SendやSyncなど一部のトレイトで採用されている機能である、既定実装と否定実装の挙動を調べた。 既定実装と否定実装について 既定実装(デフォルト実装, 自動実装, オート実装, default impl, auto impl)と否定実装(negative impl)はRust RFC 0019: Op…

Rustの組み込みマクロ

Rustのマクロの多くは macro_rules! で定義されるが、トークン列をトークン列に変換するものなら何でもマクロとして実装されうる。 Rustの標準ライブラリのマクロの多くは core::macros にて定義されている。 以下のマクロは通常の macro_rules! により定義…

Rustのマングリング(名前修飾)

Rustの生成したネイティブコードを見ると、 _ZN6thread5sleep20h87eee61de4645181cAbE のようなシンボル名が見える。この例は std::thread::sleep に対応している。このようにRustの(単相化された)アイテム(関数や変数など)の名前をリンカが認識できる文字列…

Rustのvtableの内部構造

trait objectは、型情報を忘れるかわりにvtableへの参照を持ち回すことで動的ディスパッチを実現している。 vtableを生成するコードはrustc_trans::meth 112行目にある。これによると、vtableの構造は以下のとおり。 0番目: Drop Glue をあらわす関数ポイン…

RustでPhantomDataにT以外のものを入れるのはなぜか

PhantomDataにT以外のものを入れるのは、主に3つの理由がある。 生存期間変数に言及するため。 変性を制御するため。 所有関係を制御するため。 生存期間変数に言及するため 型だけではなく、生存期間変数も、迷子になっては困る。こういうときは参照を使っ…

Rustで型の多相再帰はできない

OCamlやHaskellに比べると、Rustは多相再帰ができない場合がほとんどである。以下にその詳細を説明する。 多相再帰 異なる型引数による再帰呼び出しを多相再帰 (polymorphic recursion) という。多相再帰はPurely Functinoal Data Structuresで紹介されてい…

RustのDropの実装に対する制約とDrop Checkの規則

DropとDrop CheckについてはThe Book: DropとNomicon: Drop Checkを読んでもらうとして、この辺りの規則はコンパイラの typeck::check::dropckのコメントに解説がある。 Dropの非伝搬性 ところで、筆者が個人的に勘違いしていた点として、「 T: Drop である …

Rustのクエスチョンマーク

Rustに出現するクエスチョンマーク let f = File::open("input.txt")?; はRust 1.13で導入された機能で、ほぼ try! の構文糖衣である。 「ほぼ」というのは、 ? が将来的にはより汎用的に使えるように設計されているためで、 Result に限らない一般の std::o…

Rustのsize_of_valはどこで実装されているか

概要: std::mem::size_of_val はRustでもCでも実装できない。どこで実装されているかを調べた。 size_of_val が特殊な理由 std::mem::size_of_val は std::mem::size_of の親戚である。 size_of はCのsizeofと似たようなものだと言ってよい。 RustはCとは異…

クロージャを boxせずに 返したい: Rustのconservative_impl_traitとimplementation leak

概要: 「クロージャを boxせずに 返したい」という欲求は人類の四大欲求のひとつと言われている。 conservative_impl_trait という機能を使うことでこれをスパッと解決できるが、これは単なる構文糖衣にとどまらずRustの型システムに食い込むこともあってか…

Rustの字句

以下はRust1.15.1の syntax::parse::lexer をもとに作成したPEG風の字句規則である。 IdentStart <- [a-zA-Z_] / # Any Unicode scalar value >= 0x80 with XID_Start property IdentContinue <- [a-zA-Z0-9_] / # Any Unicode scalar value >= 0x80 wih XID…

RustのFn* trait

Rustにおけるクロージャとは、 Fn, FnMut, または FnOnce を実装した値にすぎない。これらを追ってみた。 Fnはどこから来たか まず、 Fn/FnMut/FnOnceはキーワード/予約語ではない。syntax::symbolの一覧にない。 fn main() { let Fn = 0; } そこで、広く使…

RustのSizedとfatポインタ

概要: RustにはSizedというトレイトがあり、一部の例外を除いて暗黙のうちに実装されている。Sizedが実装されていない型はDynamically Sized Typeと呼ばれ、これらのデータはfatポインタを経由してアクセスする。この仕組みを説明する。 Sizedの使い方はAPI…

combine: マクロのいらないRustのパーサーコンビネーター

はじめに Rustには有名なnomというパーサーコンビネーターライブラリがあるが、せっかく高級な型システムと最適化があるのにマクロで何とかしようとするのは勿体無いと思うので、マクロに深く依存しないcombineを使ってみた。 combineの主な特徴 parsec リス…