RustでCHIP-8のエミュレータを書いた
まえにGoで挑戦したCHIP-8エミュレータの実装を今度はRustでやっていました。 github.com/masu-mi/rusty-chip8に置いています。
反省
とりあえずstd::*
を一読するべき。
いろいろと学ぶことがたくさんあります。とりあえず下に目を通せば基本的なことはできるようになるはずと思いました。
module | メモ |
---|---|
std::option |
Some(_), None のあれ |
std::result |
Ok(T), Err(E) のあれ |
std::boxed::Box |
メモリサイズが不確定な型をヒープに配置して参照をもつために使う |
std::rc::Rc |
参照カウンタ |
std::array |
配列作る便利関数がある |
std::vec |
Vec 、可変長配列やスタックに使える, len, capacityあってgoのスライスみたいなもの |
std::collections |
一般的なデータ構造が揃ってる(VecDeque, HashMap, HashSet, BTreeMap, BTreeSet, LinkedList, BinaryHeap ) |
std::iter |
for は IntoIterator を使った糖衣構文 |
std::sync::{Arc, Mutex, RwLock, Once} |
アトミックな参照カウンタ, Mutex, RwLock, Once |
std::sync::mpsc |
キューが提供されてる、try_* がノンブロッキングにやりとりするためのメソッド |
std::env |
環境変数や引数 |
std::fs |
ファイルシステム |
std::path |
パス操作 |
std::net |
tcp, udp |
std::io |
Read, Write でGoとほぼ同じ、専用のResult, Error が定義されてる、sink(), copy(), stdin(), stdout() とか便利関数もある |
std::time |
Duration, Instant, Systemtime を知ってればOK |
std::fmt |
フォーマット |
std::thread |
スレッド |
std::process |
プロセス |
collectionsの中身を変更する
Ram実装で値の書き換えを for
ループで実装しようとしたところハマりました。理由は可変参照を使わなかったためです。
for
は IntoIterator
を使ったloopの糖衣構文です。そして Vec, &mut Vec, &Vec
で IntoIterator::into_iter()
の返値の型が変わります。
Vec::into_iter()
はvec::into_iter::IntoIter<T, A>
が使われ元の変数から所有権が移ります。そのため値を変更するという目的には使えません。ちなみに vec::into_iter:IntoIter
の定義はここです。
Vec
の中身を変更したい時には下のように可変参照を使います。
|
|
またIterator
がIntoIterator
も実装しているため下のような書き方も成立します。
|
|
loop内でlock()を取るとdropされない
したのようにlock()
をloop直下で行いsleep()
するとロックが解放されず他のスレッドを止めてしまいます。
|
|
そこでスコープを区切って確保した値の変数のスコープが早く閉じるように変更した。ちゃんと関数に分けた方が良いとは思います。
|
|
オプション解析
人気そうだったのでオプション解析ではclap
を使いました。
ビルダーパターンで定義もできるのですが手続きマクロによって下のように定義することもできます。
|
|
logger設定
ロギングでは、インタフェースを提供するlog
クレートが人気なようです。そして今回は、これに対応したenv_logger
を使いました。
main()
先頭で使いたいロガーのinit_logger()
を呼びだします。
|
|