Rustを勉強してみて、押さえておきたい点をいくつかまとめました。
周辺ツール
rustup
Rustのバージョン管理ツール。
rustupをインストールすると、通常以下もインストールされる。
- rustc:Rustコンパイラ
- cargo:Rustのパッケージマネージャ
- rust-std:Rustのスタンダードライブラリ
- rust-docs:ドキュメント
パッケージ、ライブラリ、モジュール
先にパッケージ・クレート・モジュールの関係性を伝えておくと、こんなイメージ。

クレート(crate)
バイナリやライブラリのことをRustではクレートと呼ぶ。
バイナリ:人間が読めないファイル。CPUやプロセッサをビットで直接制御したりする。
ライブラリ:何かしらのタスクを最適化するために、事前に作られたコードの集合。
パッケージ
一連の機能を提供するクレートのこと(クレートは1つでも複数でもOK)。
モジュール
一般的には、特定の機能を持ったひとまとまりの構成要素。
Rustでも同様で、クレート内のコードなどに有効であり、mod
で定義できる。モジュールの中にモジュールがあってもOK。
mod myjob {
mod cooking {
fn cut() {}
fn boil() {}
}
mod cleaning {
fn wash_dishes() {}
fn wipe_windows() {}
}
}
Cargo.toml
パッケージなどの設定ファイル。
npmにおけるpackage.jsonみたいなもの。
命名規則
基本的にスネークケース。
基本文法
定数
constで宣言。型宣言も必須。関数呼び出し結果などには使用できない。
const MAX_COUNT: u32 = 100_000;
変数
letで宣言する。mutを追加すると、mutable(可変)であることを意味する。
let mut x = 2;
シャドーイング
letで変数を上書きできる。mutを付与した宣言とは違い、型も変えて新しくセットするイメージ。
加工のために一時的に作った変数でも、そのままの名前で再加工できたりする。
let spaces = " ";
let spaces = spaces.len();
アトリビュート(attribute)
#[]
、#![]
を使用して表現される。クレート、モジュールなどに対するメタデータ。
下記コードでは、popup関数でwasm_bindgenを使用することを意味する。
#[wasm_bindgen]
pub fn popup(message: &str) {
alert(&format!("Hi, {}!", message));
}
定数・変数のbind {}
{}に変数が補完される。下記コードでは、Hi {name}, {message}!
となる。
#[wasm_bindgen]
pub fn popup(name: &str, message: $str) {
alert(&format!("Hi, {}, {}!", name, message));
}
メモリ関係
スタック・ヒープ
スタックには固定サイズのデータが格納される。
一方、ヒープにはデータサイズが不明であったり、可変なものが格納される。
ヒープを使用するとき、OSが十分な大きさの空領域を見つけ、使用中にし、ポインタ(その領域のアドレス)を返す。この一連のことを「ヒープに領域を確保する、allocateする」と呼ぶこともある。
【補足】ヒープに格納されるデータでも、一部はスタックに格納されることもある。
例えば、String型はポインタ、長さ、許容量の3つで構成されるが、これらの情報はスタックに保持され、データの中身はポインタが示すヒープ領域に保持される。
所有権
メモリ上にあるデータを参照する権利のこと。所有権をもつ変数を所有者と表現する。
ガベージコレクションに似た働きをする側面もある。
- 各値(メモリ上のデータ)は、所有者と呼ばれる変数と対応している
- 所有者は常に一つ(複数の変数が同じメモリを参照できない。後述のムーブが例。)
- 所有者がスコープから外れたら、値を破棄する(メモリ解放)
ムーブ
所有権が移動すること。
ヒープ領域の同じメモリを複数の変数が参照する場合、古い方の参照を無効にする(所有権が移動している)。あるメモリを参照する変数は常に1つになる。
let text1 = String::from("hello");
let text2 = text1; // 両者は同じメモリを参照するため、ムーブが起き、これ以降text1は使用できない。
クローン
ディープコピーもcloneというメソッドを使用することで可能。
let text1 = String::from("Clone!");
let text2 = text1.clone();
println!("text1 = {}, text2 = {}", text1, text2);
ディープコピーとは
ポインタをコピーするのではなく、実際のデータをコピーすること。
別々のデータとして扱われるため、相互に影響を与えることはない。
よく見る演算子
&
参照と借用を行うときに使われる。
- 参照:値の所有権はそのままで、所有者以外の変数がデータを参照すること。
- 借用:関数の引数に参照を取ること。
fn main() {
let text1 = String::from("Hi");
let length = calculate_length(&text1);
println!("length: {}", length);
}
fn calculate_length(text: &String) -> usize {
text.len()
}
参照・借用した値を変更するには、mut
をつける必要がある。
fn main() {
let mut text1 = String::from("Hi");
addName(&mut text1);
}
fn addName(text: &mut String) {
text.push_str(", Tom!");
}
!
マクロ(ある機能の集合)であることを表す。マクロはメタプログラミングの1つ。
println!("Hello, world!");
メタプログラミング
コンピュータプログラムそのものをデータのように扱えるプログラミング技術。(引用:Wikipedia: メタプログラミング)
あるコードを記述するために、それを呼び出すより少ないコードを書くイメージ。
関数に似ているが、Rustの場合実行タイミングなど異なる点がいくつかある。
WebAssembly関連
主要パッケージ
wasm-pack
RustをWebAssembly(以下、WASM)にコンパイルするためのパッケージ。
wasm-bindgen
JavaScriptのものをRustにインポートし、RustのものをJavaScriptにエクスポートできるパッケージ。
JSとRustの型を取り持ったり、JSの例外をRustで処理したりできる。
RustコードをWASMにビルドする時
以下のことが行われる。
- RustコードをWASMにコンパイル
- そのWASMファイルをブラウザが理解できるモジュールにラップするJavaScriptファイルを生成。(wasm-bindgen)
- pkgディレクトリを作成し、JSファイルとWASMファイルをそこに移動させる
- Cargo.tomlを読み込み、それに合わせたpackage.jsonをpkgディレクトリ内に作成する
- コピーしたREADMEをpkgディレクトリに移動
WASMとブラウザ
ブラウザでWASMモジュールを実行する時、下記を行う必要がある。
- .wasmファイルの読み込み
- インスタンス化
- 起動
そして、それをJavaScript APIで実行できる。(fetch 等)
※WASMはブラウザだけでなく、Node.jsなどサーバーでも実行可能。