2017-06-01から1ヶ月間の記事一覧

Rust unsize期待型とキャスト期待型

Rustの期待型は以下のようなデータ構造になっている。 #[derive(Copy, Clone, Debug)] pub enum Expectation<'tcx> { NoExpectation, ExpectHasType(Ty<'tcx>), ExpectCastableToType(Ty<'tcx>), ExpectRvalueLikeUnsized(Ty<'tcx>), } このように4つのコン…

Rust 関数呼び出しの期待型の伝搬

以前の記事で説明したように、Rustでは型強制や整数リテラルなどの特殊な型推論をシームレスに行うために期待型という概念を導入している。 この期待型はトップダウンに伝搬されるが、先ほどの記事で挙げた例 fn main() { let x : Box<[_]> = Box::new([1, 2…

Rustにおける演算子の型推論の特殊ルール

概要: 原則として x + y は ::std::ops::Add(x, y) の構文糖衣であるが、型推論で特別扱いされる。 演算子の脱糖 演算子の脱糖は型推論の後、HIRからMIRへの変換のタイミングで行われる。原則として x + y は ::std::ops::Add(x, y) の構文糖衣である。これ…

Rust パターンマッチの変数束縛とコンストラクタ/定数の区別

パターンマッチを持つ言語では、変数束縛とコンストラクタ/定数が構文上曖昧である場合がある。Rustでは以下の規則に従っている。 以下のように、構文的にパスであるとわかる場合は、常にコンストラクタ/定数とみなす。 :: を含んでいる場合。 (::A, self::A…

Rustで use std; が必要なときとエラーになるときがあるのは何故か

Rustでは use std; や use rand; のようなインポートが必要な場合と、逆に書くとエラーになる場合がある。 簡単に言うと トップレベルモジュールでは、書くとエラーになる(既にある名前と衝突する)。それ以外の場所では、必要な場合がある。 これは名前をロ…

Rustでunsafeが必要な操作

Rustでは unsafe の表明を行わない限り未定義動作が発生しない。コンパイラや言語仕様のミスにより未定義動作が発生しうる場合には優先的に修正される。(なお、整数オーバーフローのように特定条件下でエラーになるものであっても、正しくunwind/abortできる…

Rustコンパイラのコンパイルの流れ

Rustコンパイラは同梱のrustbuildというツールでビルドされる。これはRustとPython2で書かれている。 README.md にも説明が書かれているが、ここで改めて説明をしてみる。 ./x.py は src/bootstrap/bootstrap.py にリンクされている。これは次のような動作を…

Rustコンパイラの自前ビルド

コンパイラの動作を調べるにあたって、いちいちmasterをビルドするのは不便なので、安定版の自前ビルドを作成することにした。 $ wget https://static.rust-lang.org/dist/rustc-1.18.0-src.tar.gz $ tar xvf rustc-1.18.0-src.tar.gz $ cd rustc-1.18.0-src…

RustでOptionやResultの配列ができてしまったときの一般的なテク4つ

Vec<Result<_>> ではなく Result<Vec<_>> を得る collect() 関数を使うと、 Vec<Result<_>> を得ることもできるし、 Result<Vec<_>> を得ることもできる。変換先の型を明示することで区別する。 fn main() { // 全てSomeならSome(配列)を返し、どれかがNoneなら全体もNoneになる assert_eq!([So</vec<_></result<_></vec<_></result<_>…

Rust パターンマッチの網羅性

Rustのパターンマッチは網羅性が検査され、網羅的でない場合はコンパイルエラーになる。網羅性は以下のように検証される。 型の分類 パターンマッチの網羅性をするときには、全ての型がADTのように扱われる。つまり、有限個の引数をとるコンストラクタが有限…

Rustのmatchにおけるカンマの省略

Rustの match の腕はカンマで区切られるが、これが省略できる場合が2つある。 末尾のカンマ => { .. } の直後のカンマ fn main() { match Some(1) { Some(x) => { } // => { .. } の直後にはカンマは省略可能 None => () // 末尾のカンマは省略可能 } } この…

Rustの構造体/列挙型フィールドの並べ替え

現在の安定版では無効化されているが、Rustのbeta/nightlyには構造体/列挙型フィールドの自動並べ替えが実装されている。この動作を説明する。 例 以下のようなプログラムを書くと、現在の安定版では6が表示され、beta/nightlyでは4が表示される。 use std::…

Rustの配置構文とbox構文

概要: Rustの不安定機能である配置構文とbox構文の仕組みを説明する。 配置構文の動機 Rustの値渡しはデフォルトでムーブであり、コピーコンストラクターのような重い処理が勝手に実行されることはないから、多くの場面では値渡しのコストはそれほど高くない…

Rustの型推論の概略

概要: Rustの型推論の大枠を説明する。 なお、筆者もRustの型推論の動作を詳細に把握しているわけではない。 短くまとめると Rustの型推論はHindley-Milner型推論ベースである。したがって後方の式や文の内容から手前の型が推論されることもある。しかし以下…

Rustのtry-catch構文

Rustのnightlyに新しく入ったtry-catch関連構文を紹介する。 do catch によるcatch構文 #![feature(catch_expr)] use std::fs::File; use std::io::{self, BufReader, Read}; fn main() { do catch { let f = File::open("foo.txt")?; let mut f = BufReader…

Rustのderiveはあまり頭がよくない

概要: Rustの derive はあまり頭がよくない。 derive がドジを踏む例 derive の問題は顕在化しやすく、RustコンパイラのGitHub上でも何度も重複するissueが投げられていた。今は主に #26925 を中心に議論がまとまっているので、そちらを参照するとよいだろう…