Rustに関する世界観です。
Mozillaによるシステムプログラミング言語。
みんなから愛されて、2016-2017年のStack Overflowで「最も愛されているプログラミング言語」で一位を獲得している。
主な特徴は公式を参照のこと。
公式の入門本は以下にあります。
以下は参考までに。
関連リンク集:
Rustの根本原理は、エンパワーメント(empowerment)にあります。
これは、「プログラマとしてしっかりと活躍するための能力を与える」ということを意味しています。
僕が思うに、たしかにRust自体がとても優れた神のような言語であり、最高のツールである、ということも正しいですが、それだけではなく、「Rustを学ぶことで一流のエンジニアとして活躍できるようになるための基礎的能力を得られる」という側面が強い言語ではないかと思います。
Rustで本当にプログラミングを行うこともできますが、それよりもRustは「力を与えてくれる」のです。
なので、以下のRust Bookのsecond-editionの最初にも、エンパワーメントの原則が登場します。この本は難しいように見えて本当は簡単であるため、時間のある時に流し読みをしましょう。
Rustは、「今まで職人や限られた技術者にしかできなかった低レベルなレイヤーの処理で、古い制限や間違いを起こしやすい原因を撤廃し、きちんと正しいやり方で書くことができやすくする」といったことを目的としています。もちろんWebAssemblyなどを使うことで、Web向けにもシステムを構築できます。
Rustには、言語として面白い要素が満載です。たとえば、同じ名前の変数を覆い隠して命名することができ、一度let x = 2;と不変変数を束縛した場合、このxをx = 3;と変更することはできない(これをするためにはmutを明示的に宣言して可変変数にしなければならない)ですが、もう一度変数xをlet x = x + 1;と「同じ名前で新しい宣言を行う」ことはできます。
例外の処理やmatch式なども独自で面白いですし、所有権や参照・借用や寿命の概念によるGCの要らない安全でハイパフォーマンスなメモリ管理や、安全な並列プログラミングができる、というところは、「本当にRustを使ってやろう」という気を起こさせてくれます。ムーブセマンティクスの概念は、最初は難しいですが、「値でなく所有権を渡す」と思えば理解できます。
構造体とタプルもあり、構造体はインスタンス化できます。また、トレイトの考え方や「型に対して追加でメソッドを実装する」という考え方は、単なるクラス継承による拡張性をさらにエレガントに超越しています。標準の数値型にすら新しいメソッドを簡単に実装できます。
またCargoという開発ツールがバンドルされており、最初から依存関係を高度にこなしてくれるパッケージ管理システム兼ビルドツールとして利用できます。
また、言語的に見ていると、「やり方がC++の全面的改良版」であるという特徴があり、たとえば入力処理などでも関数に参照(ポインタと同じ)を渡すなど、今までC++でやってきたやり方(たとえばWindowsなどでのポインタの使い方)とよく似ています。全体的に見てもC++に似ているため、C++エンジニアにとってみれば「ベターC++」のように使うことができます。
こういう「言語的に面白い、新しいアイディアが満載」であるという特徴があるため、「自分の言語を設計したい」という言語設計者にとっても知っておくべき言語ではないかと思います。
Rustでは、トレイトによってオブジェクト指向を行うことができる。
メソッドの集合体であるトレイトを、型に対して実装すれば、その型でそのトレイトのメソッドを実行できるようになる。
Rustではクラスのように、型とメソッドは最初から一緒のものとしてまとめられていない。特定の型に対して、後からメソッドを「実装」する。
また、トレイトの「ミックスイン」という機能を使うことで継承も実現できる。
Rustの変数では、値を複製してコピーするのではなく、変数の所有権をムーブするのが標準。
Rustの所有権は、以下の特徴を持つ。
1.変数の所有権を別の変数に束縛してムーブした場合、ムーブされたもともとの変数は使えなくなる(所有権はひとつだけ)。
2.その代り、参照はいくらでも自由に作成できる(借用)。
3.値を変更できるミュータブルな参照はひとつだけ。
そして、変数はスタックに確保される。これにより、ガーベッジコレクションがなくてもメモリとリソースを正しく自動的に解放できる。
後日注記:すなわち、データをコピーするだけでも所有権は移動し、もとの変数は使えなくなる。例外はCopyが用意されている基本的データ型だけ。ただし、参照はいくらでも作ることができるため、関数呼び出しの際には参照を与えることで、所有権を移動させることなく同じデータを参照できる。また、値を変更できるミュータブルな参照は同一スコープの同一データに対してひとつだけであるため、関数に参照を変えてほしい時はミュータブルな宣言をして参照を渡せばいい。このようにすることで、メモリの競合と破損を防ぐ。
Rustでは、所有権と寿命の概念に基づいて、GC(ガーベッジコレクション)を行わなくても寿命以上変数が生き残る術は最初から存在しない。そして、参照はたくさんあっても、値を変更できるミュータブルな参照はひとつだけである。これによって、多くの場合、ほとんど絶対にメモリ破損が起きない。それは並列性を意識したプログラミングで有効であり、同時にGCを行わないためにC言語ほどにスピードが速く、効率的である。
まさに、神のようなメモリ管理である。最初から寿命をはっきりさせ、所有権をブロックや関数と変数の間で明確にすることで、寿命以上の参照を行おうとすると、コンパイルエラーが出る。
後日注記:実際は寿命をどれだけ伸ばすのか、ということは自分で管理することもできる模様。僕はまだそこまでBookを読めていない。
詳細は以下を参照のこと。
Java(2C.ガーベッジコレクションと例外)も参照のこと。
Rustのポイントは、「責任の所在はひとつの変数だけ」ということらしい。
ひとつの変数に値が格納されるから、ヒープ領域に格納したデータのように、どこかから変数が使われているかもしれないことを意識せず、ひとつしか値を保持する変数がないため、GCなしでもスコープを外れれば変数を自動的に破棄してくれる。
複数の変数にコピーすることができないのは残念かもしれないが、借用とかcloneでなんとかせい、ということ。
詳しくは以下が参考になる。
Rustでは、さまざまな場面で「パターン」が登場する。パターンを使うことで、変数の値の構造を記述できる。パターンの応用例は、match式を使ったパターンマッチング。
以下のページが参考になる。
2023.07.05
2023.08.14編集
Rustでは、エラーハンドリングのために例外機構は使わない。代わりに、成功したか失敗したかを判別できる型であるResult型を使う。メソッドがResult型を返す場合、エラーハンドリングを行わないとコンパイラから警告が出される。
Result型はRust以外のさまざまな言語に移植されていて、try-catchを使うよりもはるかに使いやすいと評判である。一部では「try-catchはgotoのようなもの」と言われている。
2023.07.05
Kotlinはnull安全で有名(標準では変数にnullは入らない)だが、Rustにはnullそのものが存在しない。nullを扱いたい場合は特別なOption型を用いる。Kotlinを参照のこと。
2023.07.05
Rustではヒープ領域にデータを格納することも可能。そのような場合はBox<T>を使う。
また、参照カウント方式によるスマートポインタを使うことも可能。そのような場合はRc<T>を使う。
2023.08.14
Rustでは環境の状態を持つ無名関数としてクロージャを使用できる。
クロージャの記法には、Rubyのブロックとよく似た|arg1, arg2| { ... }という縦線を使った記法を使う。
また、スレッドはthread::spawn()に対してクロージャを与えることで新しいスレッドを作れる。
use std::thread; fn main() { thread::spawn(|| { for i in 1..20 { println!("スレッドの処理: {}回目", i); } }); for i in 1..20 { println!("メインの処理: {}回目", i); } }
2023.08.14
Hello, Cargo! - The Rust Programming Language 日本語版とプログラミング言語Rustのススメ - Qiitaを参考に執筆・引用しました。
まず、ビルドツール&パッケージマネージャのcargoでプロジェクトを作る。
$ cargo new hoge --bin $ cd hoge
src/main.rsを以下のように編集する。
fn main() { println!("Hoge!"); }
あとは、
$ cargo run
でOK。自動的にビルドして実行してくれる。
以下にサンプルコードがあります。
実際のところ、Rustのコンパイラはとても優れている。人間でも分からないようなバグをたくさん言い当ててくれるからだ。
あの蟹は、めちゃくちゃ賢い。
自分で作った簡単なプログラムです。攻撃力が10のキャラと、攻撃力が1だが「1ターンごとに攻撃力が1上がっていく」キャラが戦って、いつ上がっていく方のキャラが上回るか、を計算する。
正確にいうと、「いつ上回るかを計算する」というより、その「上回っていく過程」を表示する。
fn main() { let mut x = 10; let mut y = 1; let mut count = 1; loop { print!("{} ", x); println!("{}", y); x += 10; count += 1; y += count; if (count > 100) { break; } } }
少し変えたバージョン:
fn main() { let mut x = 10; let mut y = 1; let mut power = 1; while (power <= 100) { println!("{} {} {}", x, y, power); x += 10; power += 1; y += power; } }
以下は簡単な電卓アプリ。
struct Calc { x: u32, y: u32, } impl Calc { fn add(&self) -> u32 { self.x + self.y; } fn sub(&self) -> u32 { self.x - self.y; } fn mul(&self) -> u32 { self.x * self.y; } fn div(&self) -> u32 { self.x / self.y; } } fn main() { let cl = Calc { x: 10, y: 20 }; println!("{} + {} = {}", cl.x, cl.y, cl.add()); println!("{} - {} = {}", cl.x, cl.y, cl.sub()); println!("{} * {} = {}", cl.x, cl.y, cl.mul()); println!("{} / {} = {}", cl.x, cl.y, cl.div()); }
2023.08.14
Mozilla FirefoxのHTMLレンダリングエンジン。
Mozilla Firefoxも参照のこと。
Rustのビルドツール&パッケージマネージャ。
crates.ioでは、Rustのライブラリである「クレート」が公開されている。
RedoxはRustで書かれたOS。UNIX系でマイクロカーネル。
TauriはRustで書かれたElectronと同種のGUIフレームワーク。
Electronを参照のこと。
2023.10.02
AxumはRustによる新しいWebフレームワーク。
2023.10.02
YewはRustによるフロントエンド向けのフレームワーク。VueやReactと同様のフレームワーク。
2023.10.02
nuは今までとは異なる新しいシェル。Rustで作られている。
Linuxシェルを参照のこと。
2023.10.02
Eyraはプログラムのすべて(libcを含む)をRust化することを目指したプロジェクト。
2023.10.02
Rust (プログラミング言語) - Wikipediaを参照のこと。
今僕が知ったニュースとして、マイクロソフトはRustの特徴を取り入れたプログラミング言語である「Project Verona」をGitHubにオープンソース化して提示したとのこと。
いよいよ、WindowsもRustで書かれる日が来るかもしれない。MSはWindowsの低水準コンポーネントにRustを試しているとも公にしている。僕が思うに、.NET FrameworkやC#で書かれた部分をRustで書き直せば安全かつ安定化・高速化するだろう。
LinuxカーネルでのRust言語の利用については、以下が参考になります。
WebAssemblyを使うことで、Rustで書いたプログラムをWebブラウザ上あるいはNode.js上で動かすことができます。
WebAssemblyを参照のこと。
並列処理も参照のこと。
まず、ヒープに確保される型については、束縛した時にムーブされ、もともとあった変数は使えなくなる。これはメモリ解放の二重化を防ぐ。明示的に変数のクローンを作りたいときはcloneメソッドを読みだす。
しかしながら、Copyの型については、コピーされる。これはスタックに積まれる基本型の場合が多い。数値などはCopyであるため、もともとの変数を使うことはできる。
所有権はひとつだけであり、そのため関数の呼び出しの際の引数や返り値であっても、所有権が移動するため、もとの変数は使えなくなる。
しかしながら、これではやりづらい。そのため、参照が用意されている。関数の引数に参照を与えることで、いろんな関数から変数を参照でき、所有権はもとの変数にあったままにできる。関数の引数として参照を与えることを借用と呼ぶ。
参照はいくらでも作ることができるが、通常参照は不変である。
関数の中から変数を書き換えるために参照を使う場合、ミュータブルな可変の参照を使う。この際、ミュータブルな参照は1つのスコープに必ずひとつしかないと決まっている。この制約により、データの競合を防ぐ。
Mozillaが開発した新しいプログラミング言語。