-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroad_to_rust.tex
486 lines (408 loc) · 29 KB
/
road_to_rust.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
\chapter{Rustへの道}
\begin{quotation}
Program testing can be a very effective way to show the presence of bugs, \\
but is hopelessly inadequate for showing their absence. ...
The programmer should let correctness proof and program grow hand in hand.
\end{quotation}
\begin{flushright}
--- Edsger W. Dijkstra,``The Humble Programmer'' (1972)
\end{flushright}
\section{前書き}
この種の同人誌に於ける利点は,何と言っても全く意識外の情報を仕入れる機会が得られる所だろう.
すると弊サークルのプログラミング言語大好きおじさんこと, @\_Nnwww が貴方に寄せる本記事の内容は1つしか無い,急進にして注目のプログラミング言語紹介である.
まぁ急進にして注目のといえば人の属する界隈によりけりだが,ここでは正式リリースから1年が経過し,
2016年にstack Overflowが行ったデベロッパー向けの調査にて「最も愛されている言語」
に登りつめたプログラミング言語
\footnote{stackoverflow Developer Survey Results 2016 \\
\url{https://stackoverflow.com/research/developer-survey-2016}}
「Rust」について紹介しよう.
即ち,本記事はRustが現れた文脈を共有しない読者に向け,その理念や設計を大まかに示すものである.
連絡の際は前述のアカウントに御一報下さい.文体ですか?やってみたかっただけです :)
\section{Rustとは}
Rustとは「ゼロコスト抽象化」を実現する「トレイト」ベースの静的型付き「手続き型プログラミング」言語である!完!
というのは言葉足らずの私の主観だが事実しか並んでいない筈だ.
もう少し真面目に話せばMozillaが製作中の新作webレンダリングエンジンServoの実装に
用いられているLLVMバックエンドのネイティブコンパイル言語である.
公式では安全性,速度.並行性の3つの目標にフォーカスし,それらをガーベジコレクタ無しで実現するシステムプログラミング言語である,といった紹介がなされており,
レイヤ的にはこれまでC/C++のような言語が取り組んでいた領域に昨今の知見を持ち込む進捗だと言えるだろう.
さて,少なくともこの言語の場合,来たる知見の方角を意識しつつ機能を咀嚼するとわかりやすい.といっても大別して2つだと考えられる.
即ち「関数型プログラミングから来た知見」と「同レイヤの先達 (主にC++)にて醸成された知見」である.それでは見ていこう.
\section{ゼロコスト抽象化}
実行時のコストを支払わずに強力な抽象化や安全性検査等を実現するという思想.
力の限り不適切に形容すると「あ〜HaskellがC言語並の実行速度で動かないかなぁ」という考えであり,プログラミングの理想主義である.
特定の機能というより普遍的に現れるRustの指針であり,言語機能から標準ライブラリの設計,果てはコンパイルの最適化まで及ぶ.
従ってコードを書く際のつらみも,書かれたコードのつよみも,大凡ここから発露するものである.
\subsection{トレイト}
C++やJava,C\# に代表されるジェネリクスについて思い出して欲しい.
型をパラメータTに置き換える事により,逐一具体的な型についてコピーアンドペーストしなくとも
汎ゆる型を扱える凄い奴だ.
だが,これらジェネリクスの型パラメータはそれがどういった性質の型であるか制約を課す事が出来ない.
そのため型を解決する際に「ジェネリックな関数内のどの式でエラーが起きたか」は知ることが出来るが,
「その型にどういった性質が欠如していたのか」を具体的に知ることは出来ないのである.
\footnote{C++ではテンプレートメタプログラミングに依るConceptという手法で実現可能.
\\ 言語機能としての実装が熱望されているが,C++11の頃から今日に至るまで延期され続けている...}
するとジェネリクスについて我々は考えを改めなければならない.
我々が必要なのは\textbf{汎ゆる型}ではなく,\textbf{特定の性質を持つ汎ゆる型}なのだ.
トレイトとはこの語の和訳の通り,ある型が有する「特質」乃至「特徴」を表す言語機能
だ.
此処で言う特質とは特定のシグネチャの関数群や関連する型が適切に実装されている事を指す.
簡単な例を見てみよう.(標準ライブラリのHashはもっと複雑である)
\begin{lstlisting}[language={C++},caption=Hash可能である事を示すトレイト,label=hash_t]
trait Hashable where Self : Eq {
fn hash(&self) -> u64;
}
\end{lstlisting}
これはとある型がハッシュ可能である事を示すトレイトだ.Rustではその対象となる型をSelf,
その値をselfと表現する.
大文字から始まるのが型やトレイトで,
小文字で始まるのがそれ以外の値やシンボルだと捉えて貰って構わない.
HashableトレイトはSelf型の値の参照を取り,符号無し64ビット整数型を
返す関数hashを要求する.また,トレイト名に続くwhere句という部分で,
self間の同値関係が成立する事を示すEqトレイトを実装するという制約を追加している.
これに対し簡単な実装を与えてみよう.
\begin{lstlisting}[language={C++},caption=トレイトの実装と利用例,label=hash_use]
impl Hashable for bool {
fn hash(&self) -> u64 {
if *self { 0 } else { 1 }
}
}
impl Hashable for i64 {
fn hash(&self) -> u64 {
*self as u64
}
}
struct HashTable<K: Hashable, V> { ... }
\end{lstlisting}
「impl 実装するトレイト for 対象の型」 という構文内に関数や追加の型を実装する.
ここではbool型を0と1へ,符号付き64ビット整数型をビット表現で等価な符号無しへ
変換している.実装した関数はtrue.hash()のようなメソッドチェーンで呼び出せる.
Rustではオブジェクトにメソッドが付属しているというより,
型について実装された関数の第1引数へ値を適用するのがドット演算子であるといった認
識が好ましいように思う.
すると利用例として最後の行のような構造体が定義できる(実装は省く).
ハッシュテーブルのキーと取り扱う値をそれぞれK, Vとして多相化し,
Kについてはハッシュとしての特性を持つ型という制約を与えている.
より複雑な例を扱ってみよう.
以下は1行の文字列を空白文字の類で分割して望みの型Tに変換し,
配列にまとめて返す,変換に失敗した場合はエラー情報を返すという関数だ.
\begin{lstlisting}[language={C++},caption=トレイトの複合, label=trait_cmpl]
fn parse_from_line<T: FromStr>(line: &str) -> Result<Vec<T>, Box<Error>>
where T::Err: Error + 'static { ... }
\end{lstlisting}
T: FromStrというのは文字列型からT型へ変換出来る事を示すトレイトであり,
またwhere句での追加の制約は,FromStrトレイトによって要求される「変換に
失敗した場合に出すエラーの型Err」が,Rust全体で汎用的に使われているエラーの
トレイトErrorを実装している事,加えて,T::Errの値が独立した寿命を有せる ('static) 事を要求してい
る.完全に理解する必要は無いが,オブジェクト指向における多態性と異なっ
て階層構造を持たない分疎結合であり,複数の制約を自由に組み合わせられる事に注目して欲しい.
更に,今回は立ち入らないが,トレイトは静的ディスパッチ(先述の方法)
と動的ディスパッチ(トレイトオブジェクトという機能)を切り替えられる.
RustではC++等と比べて良く統合されており,
実装側は共通でトレイトを実装するのみで良く,使用側で静的か動的か選択可能である.
言い換えれば型の解決のコストをコンパイル時,実行時のどちらで払うかが
コードに現れるということであるし,書く際はそれがすこぶる意識させられる.
ここまでで型クラスでは?と思った一部の諸兄,残念ながら現在はHigherKindType対応でないためFunctor等は努力が必要である.
RustはLLVMに依る最適化を受ける言語ではあるものの,モナ度の高まりはコンパイル時,実行時共にコストが蓄積しがちな代物であるし,
ゼロコスト抽象化と記述力向上を共に実現する言語機能として
健全なマクロやコンパイラプラグイン\footnote{ユーザが書いたRustの任意の
コードがプラグインという形でコンパイル時に走るようになる. \\
構文の拡張や,コンパイル時twitterも可能.但し現在nightlyの機能である.}
があるため,諦めるのが賢明だろう.
これらの機能については入門してからのお楽しみである.
\subsection{所有権システム}
ゼロコスト抽象化を担う象徴的な機能のもう1つが所有権システムである.
ガーベジコレクタの無いRustがコンパイル時の処理のみでメモリ安全性を得るための手法であり,
具体的には幾つかの概念,機能をまとめてこう記述される.
\subsubsection{所有権そしてムーブセマンティクス}
所有権とはあるスコープがあるリソースを所有し利用出来る権利である.
但し,所有権を有するスコープは自身が終了する際にそのリソースのメモリを開放する義
務が生ずる.
例えば変数を宣言した際にそのスコープは変数の所有権を得た事になる.
Rustは全てのリソースについて所有権が1つだけである事を要求する.
ここで重要になってくるのがムーブセマンティクスである.ムーブとは,
所有権を移す処理であり,
Rustでは代入や関数へ引数を渡すといった行為がデフォルトでムーブとなる.
例えば貴方がprintln!マクロで整数が入った変数を画面に出力しようと試みる.
すると変数はprintln!(に依り展開された関数)側へムーブされて此方からは参照出来なくな
り, それ以降に参照を試みるとコンパイル時エラーとなる.
この必要性はヒープにアロケートされた値について考えると分かりやすい.
ヒープに値がアロケートされている場合,
我々はそのポインタをスタックにアロケートし参照として用いる.
ムーブセマンティクスが無い場合,代入や関数適用の際に
値を自由に操作出来る存在がコピーされて増えてしまい,
何時メモリを開放すれば良いのか分からなくなってしまうのだ.
これらはC++から持ち込まれた概念であり,
ガーベジコレクタの無い言語にてメモリ安全性を保つ第一の矢である.
\subsubsection{参照と借用}
しかし現実問題参照が無いプログラミングは非常に不自由なものになってしまう.
そこでリソースの所有権を共有するのではなく,
条件付きで所有権を借用し,参照\footnote{Rustはデフォルトでイミュータブルを採用し
ており値も参照も通常の宣言では変更不能である.\\
何処が書き換わるか目をこらすよりも,
通常が不変で書き換え得る変数のみ強調した方が楽だからだ.
}
と書き込み可能なミュータブル参照(以降mut参照)という形で使えるようにする.
以下が借用のルールである.
\begin{enumerate}
\item 全ての参照は所有者のスコープより長く存続してはならない
\item 1つのスコープでは,次の内どちらかのみが起き得る
\begin{enumerate}
\item リソースに対する1つ以上の参照が存在する
\item リソースに対するただ1つのみのmut参照が存在する
\end{enumerate}
\end{enumerate}
このルールに抵触する場合コンパイルエラーとなるため,
関数を分けるかC/C++にあるような自由に追加出来るスコー
プ \{ \} を追加し局所的になるよう書き直す事になる.
このルールがマルチスレッドプログラミングにおけるdata raceの定義そのままである事が分かるだろうか?
所有権システムは並列プログラミングも初めから意識しており,
並列化の際に追加の条件が要請されるような事は無い.(誤用ではない.Rustにおけるス
レッドは1.10.0現在ネイティブスレッドのみだ)
このルールに依ってイテレーション中にデータを消してしまう行為や,ダングリングポイ
ンタが未然に防がれる.
\subsubsection{ライフタイム}
借用のルールはスコープ内の参照の数に関するものであった.
所有権システム最後の刺客たるライフタイムとは,
関数や構造体に表れる参照の「有効なスコープの範囲を記述するもの」だ.
\begin{lstlisting}[language={C++},caption=関数のライフタイム,label=lifetime_fn]
fn id<'a> (x: &'a i32, y: &i32) -> &'a i32 {
x
}
\end{lstlisting}
この関数で'aとシングルクォートから始まっているのがライフタイムであり,参照マーク
の直後に続いて記述する.ここでは,
「xの参照元のスコープを'aと名付けて扱おう」という意味になる.
返り値のライフタイムも'aである理由は明白であろう.xがそのまま返り値となるため,x
と返り値のスコープは共通でなければおかしいからだ.
なお関数にはライフタイムの省略ルールが有り,yはそれによって省略されているが適当
な'a以外のライフタイムが与えられている.
また,参照を持つ構造体のライフタイムについて以下に示そう.
補足すると,前節で言及した自由に追加出来るスコープ\{ \}とは7と11行目のこれである.
\begin{lstlisting}[language={C++},caption=構造体のライフタイム,label=lifetime_st]
struct HaveRef<'a> {
refi: &'a i32,
}
fn main() {
let x;
{
let y = &1;
let f = HaveRef { refi: y };
x = &f.refi; // compile error!
}
println!("{}", x);
}
\end{lstlisting}
この場合,10行目でエラーになる.
HaveRefをfに束縛した時点でHaveRefが持つrefiのライフタイム'aが7〜11行目のスコープに
確定したため,その外へrefiが持つ参照を連れ出せなくなったのである.
このように,Rustがライフタイムを追いかける事で,
関数や構造体を介した場合でもダングリングポインタが防げるようになる.
スコープを名付けて扱うという手法の背景にはML KitやCycloneといった言語における
Regionという概念が有る.
Rustでは,それに加えてC++のRAIIを組み合わせる事でメモリ安全
性を実現している.意欲的な読者はRegionの元論文等を調べてみるのが良いだろう.
\section{現代の手続き型プログラミング}
Rustはマルチパラダイムのプログラミング言語だ.従って特定のプログラミングのスタイルを強くサポートする形態をとらない.
例えばRustはオブジェクト指向プログラミング言語\footnote{ここではメッセージング指
向ではなく,Bjarne Stroustrup氏がC++に取り込みJava等でも用いられている「ユーザ定
義型としてのオブジェクト指向」に仮定する.}とは言えないだろう.
そもそもオブジェクトは無く,再現ができる機能は分割,分散されている.
\begin{itemize}
\item データ型ではなくモジュールが外部から見た構造を設定する機能を持つ
\begin{itemize}
\item なおモジュールの機能はカプセル化に留まらずより強力である
\end{itemize}
\item トレイトの「継承」
\begin{itemize}
\item この「継承」は実装しなければならないトレイトが増えるだけ
\item OOPと異なり階層構造も出来ないし多態性も無い
\end{itemize}
\item トレイトオブジェクトによる動的ディスパッチがオブジェクトの多態性に近い
\begin{itemize}
\item vtableと同様の仕組みを用いている
\item 一段階のアップキャストとも言えるか
\end{itemize}
\item メソッドチェーン記法は有る
\begin{itemize}
\item 中置演算子を自由に定義できないため,FPでも全体の流れはこれ頼み
\end{itemize}
\end{itemize}
また,Rustは関数型プログラミング言語とも言えない.相性の悪いポイントは幾つも見当たる.
\begin{itemize}
\item 高階関数と相性が悪い標準のマクロtry!が有る
\item 標準ライブラリには副作用抑制より速度を取っている実装もある
\begin{itemize}
\item ミュータブルな参照による引数を介した書き戻しなど
\end{itemize}
\item Rustは末尾再帰の最適化を保証しない
\begin{itemize}
\item LLVMに任せるのみ
\end{itemize}
\item 中置演算子は自由に定義できない
\begin{itemize}
\item メソッドチェーン記法を使う
\item 一部演算子はトレイトを実装することでオーバーロード可能
\end{itemize}
\end{itemize}
無論我々は順次問題に対して効果的なモデルを構築しプログラミングを行うため,
そういった意味合いで局所的に用いる事は有益だが,常に模倣するのは得策と言えないだろう.
ではRustは古臭いプログラミングしか出来ないのか?それも違う.
私はRustを現代の手続き型プログラミング言語だと考えている.
% \subsection{デフォルトイミュータブル}
% 今更話す事でも無いと思うが,コンテクスト云々と偉そうな事を放言してしまった為説明
% する.
% プログラムを書く際,全ての変数がデフォルトで不変であるという性質を指す.つまり,
% 通常の変数は変更する事が出来ず,特殊な修飾子を付けた変数のみ破壊的代入が可能にな
% る.プログラムが複雑になる程,どの部分が書き換えられ得るのかを把握する事がバグを抑えこむ上で
% 重要となってくるが,デフォルトでミュータブルな変数の言語では不変である事を示す修
% 飾子が氾濫し可読性が低下するため,Rustではデフォルトイミュータブルが採用されてい
% る.それでも速度にシビアな領域に取り組むこの言語では計算量優先でミュータブルな参照を用い
% る事が多いが,前述の通り借用のルールによってミュータブルな参照は扱いが厳しいため,
% 入門直後は矢鱈とミュータブルな参照を用いるべきでは無いだろう.
\subsection{式指向}
多くの手続き型プログラミング言語ではif文が有名だろう.文は式の中に組み込む事が出
来ない.
以下はC言語での条件に応じた初期化である.
\begin{lstlisting}[language={C},caption=Cにおけるif文,label=c_if]
int cond = 5;
int res = 0;
if (cond == 5) {
res = 10;
} else {
res = 15;
}
\end{lstlisting}
式指向な言語,Rustでは以下のようになる.
\begin{lstlisting}[language={C++},caption=Rustにおけるif式,label=rust_if]
let cond = 5;
let res = if cond == 5 { 10 } else { 15 };
\end{lstlisting}
この些末なコードに意味はない.文にはスコープの隔たりがあり,余計な副作用の発生や,表現が途中で切断されるといった問題に注目して欲しい.
Rustではletによる変数宣言を除き単体での文は存在しない.基本的に式でプログラミングを構成していく事から公式はRustを「式指向」な言語と称している.
しかし文が使えない訳では無く,セミコロンを式に加えて返り値が無い\footnote{これは
不正確な表現だ.詳細は入門して(以下略).}事を明示し,式を
文にすることができる.
ドキュメントでは.これを式文と表現している.
そのためお馴染み for のようなループも使用可能である.これ以上は詳細に立ち入って
しまうため,如何に整合性が保たれているかは実際に入門して確かめてみて欲しい.
何れにせよ,式指向は余計な副作用や処理のフローを切断せず,また情報量を柔軟に調整
でき,セミコロンの導入により文的にも扱えるため,従来の手続き的コードのほぼ上位互
換と言って差し支え無い筈だ.
なお,この特徴的なセミコロンの使い方はSMLやOCamlからの影響であることが明言されている.
これらを使った経験の有る諸兄ならば大体の想像は付くだろう.
\subsection{enum型とパターンマッチング}
代数的データ型,直和型,タグ付き共用体,様々な呼ばれ方をしているが,
Rustではそれをenum型と呼んでいる.
enum型は宣言した複数の選択肢(ヴァリアント)の内何れかをとる型である.
enum型による強みは,その型の値を取り出す際に必ずヴァリアントの網羅性を要求する事だ.
全てのヴァリアントの扱いを網羅できておらず,かつデフォルトのパターンも存在しない場合,コンパイルエラーとなるのである.
enum型によって得られる恩恵として
,まず \textbf{nullの無い世界} が開かれる.
値が無い可能性を有する型はenum型に依って簡単に表現できるからだ.
\begin{lstlisting}[language={C++},caption=Option型,label=option_t]
enum Option<T> {
None,
Some(T),
}
\end{lstlisting}
この場合Noneか,T型の値を1つ包むSomeの何れかがOption$<$T$>$型である.
例として
クロージャで条件を設定し,真になる値を
リストからSomeで包んで返す関数を以下に示す.
なお,実際にはイテレータという枠組みがあるためこういったコードは書くべきでない.
\begin{lstlisting}[language={C++},caption=条件に応じた値が見つかれば返す関数,label=find_if]
fn find_if<T, F>(v: &Vec<T>, f: F) -> Option<&T>
where F : Fn(&T) -> bool {
for x in v {
if f(x) { return Some(x); };
}
None
}
fn main() {
let input = vec![1,2,3];
match find_if(&input, |x| *x > 2) {
None => println!("No match found..."),
Some(x) => println!("Found a match!: {}", x),
}
}
\end{lstlisting}
補足すると,where句で2引数目の型Fに関数を示すトレイトFnを要求している.
この関数の呼び出し元は11行目であり,
その対応する第2引数には $|x| *x > 2$ という記述が有るが,これがRustのクロージャである.
Rustにおける関数は環境を表す構造体に()演算子をオーバーロードするトレイトであり,
where句を用いて制約する事で静的ディスパッチ出来る.
クロージャがヒープアロケートであり動的ディスパッ
チである言語は多いが,Rustではスタック\&静的ディスパッチによりコストを削減する.
注目して欲しいのは関数のシグネチャにOptionが明記される事と,
main関数内のmatch式である.この式はfind\_ifの返り値と,
\{\} 内の $=>$ という記号の左辺に有る「パターン」
を照合し,最初に合致する行の右辺を評価する.これがパターンマッチングである.
分岐が自然と網羅される事で関数が頑強になり,その関数により健全なシステムへと至るのだ.
エラーの際に情報を値として返したいならば,
\begin{lstlisting}[language={C++},caption=Result型,label=result_t]
enum Result<T, E> {
Ok(T),
Err(E),
}
\end{lstlisting}
がOptionと共に標準ライブラリで定義されている.\footnote{私個人としてはエラーに限らず「どちら
かの値」を表すHaskellのEitherの方が優れた命名だと考えている. \\
type aliasがあるため,EitherにResultという別名を与えれば意味付け上も問題ないだろう.}
Quick Sort,Hoare論理,CSPの作者として知られるTony Hoare氏はnullを10億ドル相当の過ちと称した.
NullPointerExeptionの悪名たるやここで補足するまでも無いだろうが,
根本的原因は殆どの値に入り込む可能性があり,かつどの関数がnullを返すのか型に現れ
ないことにある.
だがnullを廃しenum型を導入すれば,高々数行の定義とmatchにより問題は霧散する.
気付かぬ間に這いよるnullの影に怯え,実行時のチェックにコストを払う必要はまるで無いのだ.
昨今の言語ではnull対策の為だけの機能も有るが,
enum型はそれだけに留まらない.
複数の選択肢から何れかを選ぶ場面ならばいつでも有用であるし,
再帰的に扱えば線形リストや,
\begin{lstlisting}[language={C++},caption=線形リスト,label=list_t]
enum List<T>{
Nil,
Cons(T, Box<List<T>>)
}
\end{lstlisting}
赤黒木等も以下のように簡単に型付けが出来る.
\begin{lstlisting}[language={C++},caption=赤黒木,label=abt_t]
enum RB{R, B}
enum RBTree<V>{
Leaf,
Node(RB, V, Box<RBTree<V>>, Box<RBTree<V>>)
}
\end{lstlisting}
型の直和(enum型)と直積(即ちタプル,上記の例でいうConsやNodeがそうだ)を使いこなす事で,
多くの構造に対して型を付け,
安全に無駄なく取り扱える事が実感できる
だろう.
なお,此処で頻繁に用いられているBox$<$T$>$はヒープにアロケートした値へのポインタ
型だと捉えて差し支え無い.また,Rustではヒープにアロケートする類の型は基本RAIIが実装さ
れているためユーザがメモリ解放について気にする必要は無い.
Rustの標準ライブラリはリソースにタイトな領域へフォーカスしており,
値がスタック上にあるかヒープ上にあるか,
何らかの実行時チェックに依る保証が有るかといった特徴が明確に型に現れるよう設計されている.
\subsection{「例外」の無いエラーハンドリング}
ゼロコスト抽象化かつ疎結合な制約としてのトレイト,
あらかたの構造や複数の選択肢を簡単に型付け出来るenum型,
そこへ今回説明しなかったイテレータやtry!マクロを加える事で,
Rustは昨今の言語に良く見る\textbf{例外処理の機構を排する事に成功した}.
「成功」という表現は私の主観だが,
何れにせよ非常に面白い特徴の1つだと考えている.
詳細については是非入門して確かめて欲しい.
\section{Rustの門を叩く}
バージョンは執筆時点で1.10.0であり,ライブラリの一部がunstableであるが,破壊的な変更は見られなくなった.
現在は実用的な言語を目指し邁進を続けており,既にゲームエンジン,機械学習ライブラリ,
BIND9より安全である事を目指すDNSサーバ等が実装され,
特にRustによるOS,Redoxの開発には注目が集まった.無論これらはほぼ乃至純Rustによる実装である.
貴方がRustに入門するならば ``rustup''を導入し,
有志による翻訳リポジトリ
\footnote{rust-lang-ja/the-rust-programming-language-ja \\
\url{https://github.com/rust-lang-ja/the-rust-programming-language-ja}}
(拙訳も提供させていただいた)及びRustnomiconの読破を推奨する.
バージョン1.0から1周年であるが非常に多くのドキュメントが書かれ,現在も精力的に更新が続けられている.
従って今回は詳細な入門を書く事は避け,
如何なる要請や知見に基づいて彼らがRustへ至ったのか,その道筋の一端を述べようと試みた.
\footnote{残念ながら並列プログラミングを始めとし幾つかの篇を能力,期限,紙面等の都合で掲載出来なかった.
\\ 一言だけ加えると,wikipedia jaの並列アクターモデルや軽量タスクといった記述は現在では誤りなので注意.}
今や門は眼前に有る.貴方がそれを叩き,理想を探求する一助と成れたならば幸いである.