Rust の特徴、インストール、環境構築
参考資料#
- Rust の公式サイト
- いわゆる The Book と、 Rust by Example が聖書
- Rustの日本語ドキュメント/Japanese Docs for Rust
- ↑の日本語版も用意されている
- κeen,河野 達也,小松礼人「実践Rust入門[言語仕様から開発手法まで]」技術評論社(2019)
Rust の特徴#
- トップクラスのパフォーマンス
- C++ ≒ C ≒ Rust > Java, Swift, Go(2~3倍遅い) > Node.js(6倍遅い)> Ruby, Python3(30倍遅い)
- 早い理由
- マシンコードへのコンパイル
- 静的型付け
- ゼロコスト抽象化
- プログラム言語が持つ抽象化の仕組みを実行時コストなしに動作する
- 実行時コスト:実行速度やメモリ使用量
- 抽象化:注目すべき要素を重点的に抜き出す。
- 例:オブジェクト指向におけるポリモーフィズム
- Java 等は実行時に値の型を調べ、その型に対応するメソッドを呼び出す(動的ディスパッチ)
- 同じ性質を満たす方を統一的に扱えるため、柔軟性が高い
- 一方、実行時のコストがかかる
- Rust はデフォルトでコンパイル事にわかる方によって呼び出すべきメソッドを決める(静的ディスパッチ)
- 動的ディスパッチに比べ、柔軟性を欠く
- 実行時のコストはかからない
- プログラム言語が持つ抽象化の仕組みを実行時コストなしに動作する
- GC を行わない
- 組み込みなど、リソースが限られている環境にも適している
- 安全なシステムプログラム言語
メモリ安全
C と C++ の問題:メモリ安全性に欠ける
- データ転記の際のメモリ領域あふれ
- ポインタによる誤ったメモリ領域へのアクセス
- 初期化前のメモリ領域へのアクセス
- 解放後のメモリ領域へのアクセス
- データへのポインタと関数へのポインタの混同
上記の問題を防ぐための安全なロジックを組むのは開発者の役目とされる
Java 等は解決法を用意している
- ただし、リソースを必要としたりするため、組み込み系では向かなかったりする
Rust は開発者の責任だった問題をコンパイラが徹底的に検証する
型安全
正しく型付けされたプログラムが不正な動作(未定義動作)をしないように
シンタックス(文法)は正しくても、セマンティクス上問題があるプログラムをコンパイル時に見抜く
マルチスレッドプログラミングにおけるデータ競合の回避
- スレッド間でデータを受け渡したり共有するために、いくつかの方法を用意
- チャネル
- スレッド間でデータを送受信できる
- データはある一時点で1つのスレッドから所有されることになり、データ競合が起こらないことが保証される
- チャネルでは、値だけでなく、ポインタも送れる
- ロック
- スレッドがデータにアクセスするときは、最初にロックを取得する必要がある
- ある一時点で書き込みができるスレッドは1つだけとなる
- 配列などの範囲
- スライスを使って配列のある要素範囲だけへのアクセスを実現できる
- 例えば:配列の前半と後半の2つのスライスを作成し、前半を1つの、後半をもう一つのスレッドに渡せる
- スライスを使って配列のある要素範囲だけへのアクセスを実現できる
- イミュータブルな参照
- あるデータを指すポインタを作成する際、データを読み取り専用にできる(イミュータブルな参照)
- コンパイラは、イミュータブルな参照が有効な間は、参照元のデータに対する変更を許さない
- チャネル
- スレッド間でデータを受け渡したり共有するために、いくつかの方法を用意
アンセーフなコードもサポート
- ただし、
unsafeキーワードのついたブロックで囲む必要がある
- ただし、
- 生産性を高めるモダンな機能
- 強力な型推論
- 代数的データ型
- パターンマッチ
- トレイトによるポリモーフィズム
- シングルバイナリ、クロスコンパイル
- アプリをビルドすると、シングルバイナリが生成される
- クロスコンパイルにより、様々なプラットフォームに向けたバイナリを生成可能
- 多言語との連携が容易
- FFI(多言語関数インタフェース)を通じて、他の言語と連携できる
- FFI 関連のツール:bindgen, Neon, PyO3, Ruru, Rustler
- FFI(多言語関数インタフェース)を通じて、他の言語と連携できる
Rust のインストールと開発環境の構築#
- 以下が必要
- Rust ツールチェーン:
rustcコマンド,cargoコマンド,std(標準ライブラリ)rustupというツールでインストール
- ターゲット環境向けのリンカ(Linker)
- 正式には、リンケージエディタと呼ばれる
- オブジェクトファイルやライブラリを結合して、ターゲット環境の ABI に準拠した実行可能ファイル(バイナリ)を生成
- Rust ツールチェーン:
rustupの機能- 複数バージョンの Rust ツールチェインのインストールと管理
- クロスコンパイル用のターゲットのインストール
- RLS などの開発支援ツールのインストール
- stable 版だけでなく、nightly 版も管理可能
- 以下、 macOS へのインストール前提
Rust ツールチェーンのインストール#
rustupをダウンロード1$ curl <https://sh.rustup.rs> -sSf | shコマンド検索パスの設定
1$ source $HOME/.cargo/envfish の場合はこう
1$ set -U fish_user_paths $fish_user_paths $HOME/.cargo/bin
確認
リンカのインストール#
rustcはccコマンド経由でldを呼び出すコマンドライン・デベロッパ・ツールのインストールが必要
cc -vでバージョンを確認- なんか、エラーが出た
- ので解決策 → git configコマンドを実行しようとしたらxcrun: errorになった
1# 失敗 2$ cc -v 3xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist 4Use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, or use `xcode-select --install` to install the standalone command line developer tools. 5See `man xcode-select` for more details. 6 7 # ↑の解決策を参考に 8$ xcode-select -p 9/Applications/Xcode.app/Contents/Developer 10 11$ sudo xcode-select -switch /Library/Developer/CommandLineTools 12 13$ xcode-select -p 14/Library/Developer/CommandLineTools 15 16# 再度 17$ cc -v 18Apple clang version 12.0.0 (clang-1200.0.31.1) 19Target: x86_64-apple-darwin19.6.0 20Thread model: posix 21InstalledDir: /Library/Developer/CommandLineTools/usr/bin
開発環境の構築#
- VSCode を使うか、 IntelliJ のプラグインを使う
パッケージの作成、ビルド、実行#
以下のコマンドで
Cargo.tomlファイルにパッケージの情報を書くビルドは
cargo build- コードの検査
- コンパイル
- リンク
- lib クレートでは実行されない
- オブジェクトファイルと Rust 標準ライブラリなどのライブラリを結合
- ABI に準拠した実行可能バイナリを作成
実行はバイナリファイルを実行するか、
cargo runコマンドで
基本的なプログラムの内容#
ベタな “Hello world!” を出力するプログラム:
fnは関数定義- 基本構文は以下
- 引数と戻り値の型は省略可能
println!はマクロ- コンパイル初期段階で評価される
- その定義に従って別のソースコードへと展開される
- Rust の関数は(現時点では)可変個数の引数はサポートしていないが、マクロは可能
プログラムを作ってみる: 逆ポーランド記法の計算機例#
main 関数
assert_debug!はデバッグ時ビルド時のみ展開される- 要は評価、一致しない場合は、エラーでプログラム終了
rpm 関数
split_whitespace(): 空白を区切りとして、イテレータを返すparse:tokenが f64 に変換できるか試す|x, y| x + y: クロージャ(無名関数の一種)
1fn rpn(exp: &str) -> f64 { 2 let mut stack = Vec::new(); 3 4 for token in exp.split_whitespace() { 5 if let Ok(num) = token.parse::<f64>() { 6 stack.push(num); 7 } else { 8 match token { 9 "+" => apply2(&mut stack, |x, y| x + y), 10 "-" => apply2(&mut stack, |x, y| x - y), 11 "*" => apply2(&mut stack, |x, y| x * y), 12 "/" => apply2(&mut stack, |x, y| x / y), 13 _ => panic!("Unknown operator: {}", token), 14 } 15 } 16 } 17 stack.pop().expect("Stack underflow") 18}apply2 関数
<F>: ジェネリクスFはwhere節で指定したトレイト境界を満たす型なら、どれにでもなれる
デバッガーの設定#
参考:https://nao_tuboyaki.gitlab.io/posts/2020/04/29/rust-vscode/
VSCode での前提
- 拡張機能「CodeLLDB」を入れる
Cargo.tomlが直下にあるディレクトリで「構成の追加」- 自動で設定が以下のように追加される
1{ 2 // Use IntelliSense to learn about possible attributes. 3 // Hover to view descriptions of existing attributes. 4 // For more information, visit: <https://go.microsoft.com/fwlink/?linkid=830387> 5 "version": "0.2.0", 6 "configurations": [ 7 { 8 "type": "lldb", 9 "request": "launch", 10 "name": "Debug executable 'rpn'", 11 "cargo": { 12 "args": [ 13 "build", 14 "--bin=rpn", 15 "--package=rpn" 16 ], 17 "filter": { 18 "name": "rpn", 19 "kind": "bin" 20 } 21 }, 22 "args": [], 23 "cwd": "${workspaceFolder}" 24 }, 25 { 26 "type": "lldb", 27 "request": "launch", 28 "name": "Debug unit tests in executable 'rpn'", 29 "cargo": { 30 "args": [ 31 "test", 32 "--no-run", 33 "--bin=rpn", 34 "--package=rpn" 35 ], 36 "filter": { 37 "name": "rpn", 38 "kind": "bin" 39 } 40 }, 41 "args": [], 42 "cwd": "${workspaceFolder}" 43 } 44 ] 45}ブレイクポイントを置いて、デバッグ実行(F5)で思ったところで止まったら OK
ツールチェインの補足情報#
プラットフォーム・サポート・ティア#
- プラットフォームごとのサポートレベルを Tier1~3 で分類
リリースサイクル#
- Nightly チャネル
- 毎晩新しいリリース
- unstable な機能も含む
- Beta チャネル
- 6週間ごとに最新の rust コンパイラや標準ライブラリのソースコードから beta リリースが作られる
- beta リリースから6週間経つと stable リリースに昇進する
- Stable チャネル
- 広報互換性が保たれるようにしてる
- ポイントリリース
- stable としてリリースした後に重大な問題が見つかった場合に行われる緊急リリース
エディション#
Stable では、前のバージョンのコードが動かなくなるような新機能がリリースできない
これを解決するために Rust 1.31.0 から2つのエディションが導入された
- 2015 エディション:Rust 1.0.0 と後方互換性が保たれる仕様
- 2018 エディション:新たな予約語などが取り入れられ、2015エディションとは一部が非互換の仕様
Cargo.tomlに下記のように書いて選択上記を省略すると、 2015 エディションが指定されたと解釈される
エディションは 2, 3年のペースで追加される見込み。古いエディションの廃止予定はない。
cargo fix: 新しいエディションへの移行を支援するコマンド
rustup の機能#
rustup showでインストール済みのツールチェインと現在アクティブになっているツールチェインを表示rustup installで追加のツールチェインをインストールnightlyとか
rustup updateでインストール済みのツールチェインと rustup 自体を最新版にアップデート- 定期的に実行すると良い
- 特定のパッケージのみ nightly を使用することも可能
ここに掲載する記事はまだありません。
