Rust演習の記録
Rust備忘録
2025/4/23
- JavaScript/TypeScriptしかまともに書けない状況の打破
- 学部授業レベルでCは書いてたけど、低レイヤーのことを学ぶきっかけがほしい
- WebAssemblyにもつながる
あたりをモチベにRustの勉強をしてます。
2025/04/23現在、The Rust Programming Language 日本語版を12章まで読んだり写経したりそれを改造したりしたところ。 ここまでで区切りにして、アウトプットとしてなにかツールを作ろうとしているので、一旦ここまでで公開します。
やってて色々わかんなくなったら、また立ち返って追記/修正していく予定。
アウトプット
手元で作成したものは、jonnity/rust-exerciseにコミットして、公開してます。
へ~って思ったとこ
2章. 数当てゲームのプログラミング
let guess: u32 = guess.trim().parse().expect("Please type a number!");
みたいな、変数名使い回す (shadowing) 書き方ありなんだ- 型付けがしっかりしてるのと、再定義を許可することって両立するんだね
- 可読性とかの話としては同列に感じる (=再定義を乱用したら、意味わからんコードは書ける) けど、メモリ管理の観点からしたら、全然別の話ってことなのかも
3. 一般的なプログラミングの概念
const
ってそりゃ定数を表すよね- Javascript/Typescriptの、再代入を許さないだけのものを
const
で扱うの、なかなかな気がしてきたね
- Javascript/Typescriptの、再代入を許さないだけのものを
- 言語仕様として
let
で定義する変数はグローバル変数で定義できないという縛りがあるの、いいですね。- こういう仕様ってshadowingとは違って、可読性のためのものなのか?メモリ安全性にも寄与する?
- 型付けが盤石なら、メモリ的にはグローバルでも一定だから、可読性のためなのかな
- 整数の基準型は
i32
、浮動小数点の基準型はf64
なんだ- それぞれ↓の記載はあったけど、なんでなんだろ
- 「64ビットシステム上でも、 この型 (
i32
) が普通最速になります。」 - 「なぜなら、現代のCPUでは、(
f64
が)f32
とほぼ同スピードにもかかわらず、より精度が高くなるからです。」
- 「64ビットシステム上でも、 この型 (
- それぞれ↓の記載はあったけど、なんでなんだろ
- ↓の記述 (Rustが配列の添字が適切かどうかをチェックするという話) は、他の言語だと実現が難しいんかな
- 実行時の動作だから、なにもしないほうが楽というのはそりゃそうなんだろうけど、やってやれないことはない話?
低レベル言語の多くでは、 この種のチェックは行われないため、間違った添え字を与えると、無効なメモリにアクセスできてしまいます。
- 仮引数 ("parameter") と実引数 ("argument") って概念、確かに両方とも引数って読んじゃうから意識的には区別できてなかったな
- この辺、言語作るとかの水準の話しなければ、みんなそんなもんなのかしら
- ブロックの中 (最後?) の行にセミコロンを含むかどうかで、その行が式か文かが決まって、それによってブロック自体も式か文か決まるってこと?わかりにくくない??
- やってたら慣れてきた。最後だけだし、まあ大丈夫な感じする
if
を式とすれば、三項演算子っていらないのか- 三項演算子的な書き方をしたいけど、わかりにくいよな~ってときもままあるから、これはいい仕様に思える
4. 所有権を理解する
- 所有権って何?と思ってたけど、「メモリのヒープ領域の管理のための仕組み」だという原理のとこから説明してもらえるから、やっぱこういう公式のドキュメントは読むべき
- 所有権という概念を成立させたまま、参照を使うとやりやすい、という説明の流れで、だいぶやりたいことがわかった気がする
- とはいえ、理解が浅いからあんまなんも言えんかも
5. 構造体を使用して関係のあるデータを構造化する
- ユニット様構造体、トレイトも何もわかってないからあれだけど、単にメンバを持たないクラスのインターフェースに使うみたいなこと?この辺に当てはめて考えるとわからんくなるんかな
- あとはまあ、そういう書き方なのね、という感じ
6. Enumとパターンマッチング
- typescriptの
enum
の型がゆるゆるだって話を踏まえてみるとすげーって感じ if let
、この動作をif let
で書くの、いまいちよくわかってない- 動作がよくわかってないのか、英語がよくわかっていないのか
- Rustの「if let」とは何なのか?@Qiitaのおかげでだいぶ飲み込めた。The bookの例が悪い
7. 肥大化していくプロジェクトをパッケージ、クレート、モジュールを利用して管理する
- nodeの
package.json
と比べて、デフォルトのcargo.toml
はシンプルでいいよね:src/main.rs
/src/lib.rs
がcrate rootになるよって話に関連して - 標準非公開なの、いっぱい
pub
って書くことになって大変な気もするけどそんなもん?- むしろデフォルト
public
なTypescriptが変な気もするね - enumの要素はデフォルト
pub
らしいし、まあそんなもんか
- むしろデフォルト
- あとはまあ、書き方って感じ
8. 一般的なコレクション
String
とstr
は、所有権がうまいことなるように実装されてるよってくらいしか理解できんかった- それで困らないんだろうな、という感じはする。困ったら困ったときにもう一回見よ
- 普通にUnicodeとかのことももうちょっと知っておきたい気もする
- そもそも興味あるっちゃある
or_insert
がその値への可変参照を返すのなんなん?わけわからんくならん?
9. エラー処理
9.3. panic!すべきかするまいか
で、2. 数当てゲームのプログラミング
で作ったものの改良が提案されて、それを実装しようとしたら、モジュールシステムがあんまり理解できていないことがわかったmod
はブロックを取るかどうかで、モジュールの構成も、モジュールの読み込みもどっちもやる予約後なんだね
- あとは、
try
/catch
でできるようなことは、Result
とmatch
とかでできるよって感じに理解
10. ジェネリック型、トレイト、ライフタイム
孤児のルール(orphan rule)
(外部の型に外部のトレイトを実装できない: 型とトレイトのどちらかはローカルにないといけない) で、二重定義が防げてるのいいっすねlargest()
でClone
もCopy
も不要にする書き方は、↓みたいなのでできた。list
で受け取ったVector
の参照から、その値の参照を取り出して最大値を見つけて、その参照をそのまま返せば、largest
内で値そのものを扱ってないからOKってことかも
1fn largest<T: PartialOrd>(list: &[T]) -> &T {
2 let mut largest = &list[0];
3 for i in 0..list.len() {
4 if &list[i] > largest {
5 largest = &list[i];
6 }
7 }
8 largest
9}
- 関数のライフタイム注釈って、呼ぶ側で指定することもあるのかな?
- 型注釈でも、渡した変数の型で指定するだけだったりするし、そんなもんか
- ライフタイムという概念があるということは理解した
- あとは書いて、エラーがでたらまた考えよう
- 概念もわからんと、エラー内容がわからんすぎるのでね
11. 自動テストを書く
- 言語仕様としてテストがあると、非公開関数のテストもできるっちゃできるのか
- 基本的には要らない?気はするけど、そのへんの考え方わかんないや
12. 入出力プロジェクト:コマンドラインプログラムを構築する
- 標準エラー出力って概念あるの初めて知った
- 確かにエラーメッセージがリダイレクトされても困るのか
- そうなってるツールは使ったことあるかもしれんけど、全然意識できてなかった
- CLIツール周りの話は、
main.rs
/lib.rs
の組み合わせが実際どうなるのかがイメージついて、だいぶ雰囲気掴めてきた感じする