Rust (プログラミング言語)

開発体系

Rustはオープンソースのコミュニティベースで開発が進められている。プロジェクトの主管はRust Project Developers（Rust開発チーム）である。2018年現在、言語発明者のグレイドン・ホアレはプロジェクトチームから外れている。プロジェクトの全てのソースコードはgithubで一般に公開されており、コミュニティメンバーの協力により改良が進められる。プロジェクトの大部分のコミットはコミュニティメンバーによるものである。
Mozillaの理念を守り、Rust言語は社会に開かれており、言語やツールに対する仕様の提案はRFCの形で取りまとめられ、関連するチケットで仕様詳細について利用者から感想や提言を受けている。
言語やコアライブラリを開発するRust開発チームはServo（ウェブブラウザ用レイアウトエンジン）やRustコンパイラの実装経験を通して言語を改良している。例えば、C言語とRustを連携させるコードを自動生成するbindgenは元々は外部開発者が開発していたが、Mozilla Servo開発チームがServoの開発で利用するためにC++とRustを連携させるコードも自動生成できるよう改良を重ね、現在はServo開発チームと密に連携しているRust開発チームに主管を移行してServoの開発と共に改良が続けられている。

パラダイム

言語実装手法においてのプログラミングパラダイムは特定の実装手法に限定されない非純粋なマルチパラダイムプログラミング言語である。文法の表面的な記述は手続き型プログラミング、ブロックコードのまとまりの意味論は関数型プログラミング、型システムを用いたオブジェクト構造はオブジェクト指向プログラミングのパラダイム特性を持つ。特定のプログラミングパラダイムのみを使用してソースコードを記述することはなく、要所々々の必要な所で必要なパラダイムを使用してソースコードを記述することになる。
ソースコードをターゲットプラットフォームに最適化したオブジェクトファイルにコンパイルするコンパイル言語のパラダイム特性を持つ。多くのスクリプト言語が持つインタプリタ機能や、SwiftやGoが提供するようなREPL機能のパラダイム特性は持たない。
その他のパラダイムとして、関数の入出力パラメータにジェネリック型を指定するジェネリックプログラミング、非同期機能を実現する並行計算のパラダイム特性を持つ。

基礎文法

Rustの基礎的な文法はC言語やC++に似て、波括弧で囲まれたブロックコード{ ... }、if, else, whileなどの制御フローキーワードを持つ。
全てのC言語やC++のキーワードが実装されているわけではなく、一方で幾つかのRustの制御命令（パターンマッチのためのmatch）はそれらの言語を習得したプログラマにとっては馴染みが少ないものも存在する。Rustの命令文は、表面的なC言語やC++との文法の類似性にも関わらず、意味論的にはML系言語の命令式に近しく、関数本体のほぼ全ての部分は制御フロー演算子でさえ「文（statement）」ではなく「式（expression）」である。例えば普通のif式もC言語で言う所の条件演算子であり、if式の結果として返り値を返す。
ブロックコード内の命令文のセパレータにはセミコロン（;）を用いるが、C言語のそれと異なりRustのセミコロンは直前の命令文がブロックコードで括られる式の途中式であることを宣言するためのものである。セミコロンを末尾に置かない命令文はブロックコードの最終的な評価式として扱われ、その式の結果がブロックコードの外へ戻り値として返される。

Hello World

「Hello, world!」を標準出力に出力するHello worldプログラム。
fn main() {    println!("Hello, world!");}

階乗

階乗を求めるプログラム。if式の結果として1もしくはn * fac_recursive(n-1)を返し、関数の結果としてif式の結果を返す。
fn fac_recursive(n: u32) -> u32 {    if n <= 1 {        1    } else {        n * fac_recursive(n-1)    }}

型とポリモーフィズム

この言語の型システムではHaskell言語に倣い「型クラス」を用いることができる。これはアドホックな多相性を容易にするものであり、可変型宣言により実現されるものである。高カインド多相性など、Haskell言語にある他の特徴はサポートされていない。

型システム

Rust言語が備える型システムは、impl（実装）、trait（トレイト）、struct（構造体）およびenum（列挙型）を基本として構成される。implが他の言語におけるクラスに近い役割を果たし、継承とポリモーフィズムはtraitによって提供される。traitにはメソッドを定義することができ、traitで宣言されたメソッドはimplによってstructへミックスインされる。structにはフィールドが定義可能で、traitとimplはそれ自身にはフィールドは定義できない。enumには複数種類の型のカテゴリ変数が定義可能で、数値型、文字列型、オブジェクト型などの複数の状態を選択的に持ちうる。菱形継承問題を回避するためにtraitのみが継承が可能である。
変数の型を決定する型システムは静的型付けかつ強い型付けである。静的型付けと動的型付けの区分においての型付けは、コンパイル時に全ての変数に対して型を決定する静的型付けのみをサポートしている。そのため、Perl、Pythonのようなインタプリタ言語で見られるような、実行時に変数の型を動的に上書きすることはできない。強い型付けと弱い型付けの区分においての型付けは、実行時に変数の型を型変換（アップキャスト、ダウンキャスト、クロスキャスト）およびボクシングをすることを許さない強い型付けのみをサポートしている。C言語、Javaは実行時に型変換をすることを許す弱い型付けをサポートしているが、Rust言語ではそのような型変換は認められていない。これら二点の静的型付けかつ強い型付けの特性により、変数の型は宣言時のもので決定的に固定される。

型推論

Rust言語ではキーワード「let」で宣言された変数に対して、左辺を変数、右辺を値とする等号式（var = val）で変数値の代入命令がなされた時に、「左辺の変数の型」は「右辺の値の型」であると型推論がなされる。変数の宣言には必ずしも型を決定するための初期値を必要としない。変数の宣言時に初期値が与えられた場合は「変数の型」は「初期値の型」であると型推論がなされるが、初期値が与えられなかった場合は以降のブロックコード中のその変数へ値が初めて代入された時に「左辺の変数の型」は「右辺の代入する値の型」であると型推論がなされる。変数への値の代入を複数回行う場合はキーワード「mut」を付与して宣言する必要がある。変数への代入が型不一致により失敗した場合にはコンパイル時にエラーを検出する。

ポリモーフィズムの実現

ポリモーフィズムを実現するため、構造体のフィールドおよび関数の入出力値は特定のトレイトの実装をするジェネリック型を指定することが出来る。そのような定義の中では、ジェネリック型で型が宣言された変数および入出力値はそのトレイトの特性のみ使用できる。これはジェネリック関数が定義されるとすぐに型判定ができることを意味している。これはC++のダック・タイピングで具体的な型がインスタンス化されるまで判定できないテンプレートとは対照的である。しかし、Rustのジェネリクスの実装はC++のテンプレートの典型的な実装と似ており、インスタンス化ごとにコードの個別のコピーが生成される。これはモノモーフィゼーションと呼ばれ、JavaやHaskellで通常使用される型消去方式とは対照的である。モノモーフィゼーションの利点は特定のユースケースごとに最適化されたコードであり、欠点は結果のバイナリのコンパイル時間およびサイズが増加することである。Rustのトレイトを用いたポリモーフィズムの実現は、実行時のオーバーヘッドがない「ゼロコスト抽象化」と表現されている。

リソース管理

Rustはメモリやその他リソースの管理にRAIIを採用しており、リソースの利用区間をコンパイル時に静的に検証するボローチェッカー（borrow checker）という機能で実現されている。ガベージコレクションや参照カウントとは異なり、コンパイル時に静的にリソースの利用区間を検証することで、実行時のリソース管理コストを少量に抑えている。

ボローチェッカー

一つのリソースは一つの所有者（変数やブロック）のみに関連付けされるという制約がRust特有のリソース管理機能として存在する。これは、あるリソースの所有権（ownership）はある所有者（owner）が持っている、のように表現される。同時に、リソースの所有権を複数の変数が持つことは出来ない。これはC++のスマートポインタの一種であるunique_ptrの振る舞いに似ている。ボローチェッカーは所有権の競合および不正利用を検証する。
リソースには参照（&記号）の概念が存在し、これは所有権の概念と並行して扱われる。所有権は一つの所有者しか持てないが、参照は複数の所有者が持ちうる。参照は同一のリソースを複数の箇所で利用するために利用される。ただし、所有権によるリソース管理は有効であり、所有権が解放されたリソースを指す参照は同時に無効化される。ボローチェッカーはこの参照についてもライフタイム（lifetimes）としてリソースの生存期間を検証する。
ボローチェッカーはリソースの所有権とライフタイムの両方を静的に解析することで、ヌルポインタや不正なメモリ域を指すポインター、リソース利用競合を制限したメモリセーフな安全性を実現している。

特異なリソース型

リソースのメモリ確保は基本的にはスタックメモリを利用しており、ヒープメモリを利用したメモリ確保はBoxやVecなどの特定の型のみで限定的に利用されている。
コンパイル時に型のサイズが決定できない可変長配列を表すような型はヒープメモリを利用するBox型を使用してリソースを管理する。Boxリソース自体はスタックメモリで管理されるが、Boxリソースが所有権を持つ実態のリソースはヒープメモリで管理される。標準のヒープメモリ確保にはjemallocを利用するが、対象プラットフォームやビルド時の指定により他のメモリ確保APIを利用することもある。ヒープメモリはスタックメモリに比べて速度性能が落ちるため、必要時にのみ限定的に利用されている。

ライブラリ

Rustのライブラリはクレート（crate）という呼称で提供される。多くのクレートはcrates.ioで公開されている。同サイトはバージョン毎のソースコードをアーカイブとして提供している。クレートは必ずしもcrates.ioに登録されている必要はなく、Webサーバやファイルシステムを指すURIで指定することもできる。ライブラリはソースコードプロジェクトで配布されることが一般的だが、コンパイルしたバイナリライブラリファイル（拡張子rlib）で出力することも可能である。

コアライブラリ

コアライブラリはcoreの名称で提供されている。このライブラリは標準ライブラリに依存しない基幹ライブラリであり、一切の上位ライブラリ、システムライブラリ、libcライブラリにリンクしていない。コアライブラリは最小限であり、ヒープ割り当てを認識せず並行性や入出力も提供していない。それらのことはプラットフォームへの調整が必要であり、このライブラリはプラットフォームに依存しない。

標準ライブラリ

標準ライブラリはstdの名称で提供されている。このライブラリは基礎的な型（Vec<T>やOption<T>）、言語の基本の処理、標準のマクロ、入出力（I/O）、マルチスレッドなどの機能を提供する。標準ライブラリは標準でリンクしてソフトウェアがビルドされるが、より根幹的なソフトウェアやリソースの小さい組み込み環境ではリンクを外してソフトウェアをビルドすることができる。

開発ツール

Rustの開発ツールは独立したソフトウェアとして提供されている。

rustc

rustcはRustで記述されたRustソースコードをコンパイルするコンパイラ（処理系）である。コンパイルの成果物として中間コード、および実行ファイル、静的ライブラリ、動的ライブラリを出力する。rustcはクロスコンパイルを可能とし、Windows、Linux、macOS向けの実行ファイル他、AndroidやiOSで動作するライブラリをホストマシンで出力することができる。
対象プラットフォームは完成度に合わせて３つのティアに分かれている。ティア1はバイナリリリースが提供されており、自動ビルドと自動テストが整備され、それらが安定して成功（パス）することが保証されている。
ティア2はバイナリリリースが提供されており、自動ビルドと自動テストは整備されているがテストが成功することは保証されていない。ティア3はソースコードとしては対応しているが、自動ビルドと自動テストの動作が保証されておらず、公式リリースは提供されていない。
Windows、Linux、macOS向けのRustコンパイラはティア1でリリースされている。Android、iOS、WebAssembly向けのRustコンパイラはティア2でリリースされている。
Rust 1.12版より導入されたMIR (Mid-level IR) によって、コンパイルと実行時間の迅速化ならびに型チェックの正確性の実現が図られている。

機能

rustupはRustプロジェクトがリリースしているコンパイラ（rustc）、ビルドツール（Cargo）などのツールチェーンをインターネットを経由してホストマシンにダウンロード、インストールおよびマネージメントする機能を提供する。インストール対象のツールチェーンのバージョンは、安定版、ベータ版、ナイトリー版の全てを含んでおり、利用者が必要とするバージョンを指定してダウンロードすることができる。また、ターゲットプラットフォームについても全ての種類を含んでおり、ホストマシンと異なるプラットフォーム（例えば、ホストがmacOSであってもWindowsやAndroid、iOS）のコンパイラをインストールすることができる。この場合、コンパイラはクロスコンパイラとして動作してターゲットプラットフォームに合わせたビルドを実施する。

歴史

Rust 1.13版以前はシェルスクリプトで実装されたrustup.shが公開されていた。これと並行してRust言語で実装された同等機能を提供するrustup.rsの開発が進められており、Rust 1.14版でrustup.shは非推奨となり、Rust 1.14版以降はrustup.rsが公式リリースとして提供されている。

評価

Rustは2016〜2019年に渡ってStack Overflow Developer Surveyで「最も愛されているプログラミング言語」で一位を獲得し続け、プログラマの好意的な評価は多い。
一方で、Rustは学習難易度が高い言語とも考えられている。多くのRust初学者のプログラマにおいて、自身が正しいと思って書いたソースコードのコンパイルに対してコンパイラ（ボローチェッカー）がエラーを検出する、「ボローチェッカーとの戦い」（fighting with the borrow checker）が発生しがちである。小さなアプリケーションの実装について同時期に言語開発されているGo言語と比較した場合、Rust言語よりGo言語の方が開発効率が良いという評価がある。学習難易度の高さは開発チームも認識しており、2017年ロードマップでは学習曲線の改善を目的として挙げていた。
Rustの実行時速度性能は同じくコンパイラにLLVMを利用している場合のC言語と同等程度であり、一部の処理ではC言語を上回った速度が確認されている。2018年2月時点で、ウェブサーバアプリケーションの汎用処理では速度性能の良いRust製ライブラリは開発が進んでいない。単純なテキスト処理では速度性能は良い。

誕生

2006年、Mozillaで働いていたグレイドン・ホアレは現代のインターネット環境で高い並行性と高い安全性が求められるシステムプログラミング言語としてC言語やC++に代わりうるプログラミング言語 Rust言語の開発に着手した。MozillaがRustの開発に関わりはじめたのは2009年で、Rustは2010年のモジラ・サミットで公に姿を表した。RustソースコードをコンパイルするRustコンパイラは、初期の頃はOCaml言語で作られたコンパイラ（rustboot）が用いられていたが、2010年にはRust言語自身でRustコンパイラを作るセルフホスティングへ移行したコンパイラ（rustc）の開発が始められ、翌年にはブートストラップ問題を解決した最初の完動品が完成した。この時よりRustコンパイラはコンパイル基盤にLLVMを用いたものとなった。

0.x版

プレアルファ（0.1版）と呼ばれる最初のバージョンは2012年1月にリリースされた。Mozillaはこれを新しいモノ好みの人やプログラミング言語愛好家のためのアルファ版と位置づけていた。最初の安定版である1.0版がリリースされるまでの0.x版リリースでは、いくつもの大きな破壊的な仕様変更が言語およびライブラリに加えられた。
変数名や関数名など識別子は、この言語の開発の初期の頃は、ASCII文字以外の文字を使うことが禁じられていた。言語についてのある質疑応答の中で、現場の非英語圏のプログラマーのほとんどが識別子にはASCII文字を使っていると述べられていた。しかしその制限は反論を引き出すことになった。それにより、2011年2月に言語に変更が行われ、この制限は削除された。
型判定は、0.4版以前の従来の静的型付けに加えて、型状態システムをサポートしていた。型状態システムは、特別なcheck文を使用してプログラム文の前後での型決定をモデル化した。C言語やC++コードでのアサーションの場合と同様に、プログラム実行中ではなくコンパイル時に型不一致を検出する。型状態の概念はRust特有のものではなく、NILで採用されていたものである。実際にはほとんど使用されていなかったため型状態は削除されたが、ブランディングパターンで同じ機能を実現できる。
オブジェクト指向のシステムは、0.2版から0.4版にかけて大きく変わっていった。0.2版で初めてクラス（class）が導入され、0.3版でインターフェース（interface）を通したデストラクタとポリモーフィズムが追加され、0.4版で継承を提供する手段としてトレイト（trait）が追加された。インターフェースはトレイトに一部の機能が統合されて、異なる不要な機能として削除された。クラスもまた削除され、構造体とトレイトを使用したミックスインに置き換えられた。
コアのメモリモデルは、0.9版から0.11版の間、2つのビルトインのポインタ型（ヒープメモリ型~とガベージコレクション型@）を機能を単純化するために用意していた。それらは、標準ライブラリのBox型とGc型で置き換えられ、Gc型は最終的には削除された。
2014年1月、Dr. Dobb's Journalの編集長アンドリュー・ビンストックはD言語やGo言語、Nim言語と同様にC++の競争相手になる機会を得たとコメントした。ビンストックによると、Rustは非常にエレガントな言語として広く見られているが、バージョン間で繰り返し大きく変更されたため普及が遅れているという。

1.x版

2015年5月16日、安定版となるRust 1.0がリリースされた。1.0版の後、安定版およびベータ版が6週間おきに定期リリースされている。またナイトリー版が毎日リリースされている。新たな機能はナイトリー版で開発が進められ、ベータ版で動作が検証されている。
2016年8月2日にリリースされたFirefox 48にはRustで書き直されたメディアパーサが組み込まれており、Mozillaが開発しているブラウザのFirefoxにおいてRustで書かれたコードが書き加えられる初例となった。
2016年9月にRustはFedora 24の標準コンポーネントに加えられ、RPMのパッケージ管理システムを用いてのインストール作業が容易化されている。

2018年版

2018年12月6日にバージョン1.31がリリースされた。今回からエディション制が導入され、最新版は"Rust 2018"、従来版は"Rust 2015"と呼ばれることになる。言語機能への破壊的変更は新しいほうのエディションで行われるが、互換性を損なわない改良は引き続き両者に適用される。また、2015年版から2018年版へはcargo fixでトランスコンパイルできる。