RustでGithubのissueひっぱてくるCLIアプリを書いた

Ruby、Elixirときて完全に別軸の静的型付け低級言語としてRustで遊んでいる。
お正月に泣きながらRustのコンパイラといろいろしてた。

github.com

ユーザー名とレポジトリ名を下のように渡すと
github-issue rails rails  

 number |title                                                                                          |created_at           |

38237  |Update caching_with_rails.md                                                                   |2020-01-15T02:29:53Z |

38235  |Move advisory lock to it's own connection                                                      |2020-01-14T17:54:27Z |

38234  |Rails 6 : config.require_master_key=true doesn't raise an error if key does not exist          |2020-01-14T15:49:12Z |

38229  |Prevent `has_one` `build_association` from `touch` parent record if the record isn't committed |2020-01-13T22:11:50Z |

38226  |Active Record unit tests fail with MySQL 8.0.19                                                |2020-01-13T14:59:02Z |
 

という感じで標準出力するアプリを書いた。プログラミングElixirの題材をRustで書き直したやつ。まだまだテストでのモックとかやるべきことはいっぱいある。

Rustつまづきポイント

そもそもコンパイラになんとか通してもらうために無理した書き方をしている自覚があり、しかもきれいにする方法がわからないので書くたびに自分の無力感が高まって泣いていた。

文字列型の種類が複数

Rustでのいわゆる文字列には、メモリ長が決定されている組み込みの&strと、メモリ長が固定されていない標準ライブラリにあるString型がある。String型はヒープ(スレッド間で共有できるメモリ領域)に格納できて可変。 実際にコード内で "string"のように書くと&str型になるのでGithubからのレスポンスをStringとして扱う時に色々変換しなくてはならず辛かった。多分もっといいやり方があると思うので助けて。

Result型とOption型

つまづきポイントに入れてるけど同時にRustの優れてるポイント。多くの関数がこの2つのうちどちらかを返すことが多い。
OptionはNoneもしくは値を返すという型。 Noneはnullのようなもの。 返り値書くときにはSome(1)Noneという書き方をする。

Resultは例えばrunみたいな関数があったとして
pub fn run(args: Vec<String>) -> Result<i32, Box<dyn Error>>
ようにエラーを返すかもしれないことを明記できる型。
返り値書くときにはOk(1)Err(ParseError)という書き方をする。
これらの型で返された値はunwrap()をするか process(args)?のように末尾に?演算子をつけて例外やNoneが出たら関数全体としてエラーやNoneを返すということを明示することができる。しかしどんな形がベストなのかイマイチつかめない。ここではめったにエラー起きないだろうってところはunwrap()でそれ以外は?という感じで使えばいいのだろうか。
ちなみにNoneやErr()に対してunwrap()するとpanicする。unwrap_or_else()なんかもあるのでやりようはありそう。

所有権

もう全然スマートな解決方法がわからない。無理やりclone()したりして逃れている。
rows.as_array().unwrap().to_owned()
こんなコードも書きながらもっといいやり方ないのかと泣いていた。

Rustのよかったところ

よかったところというとおこがましいという気持ちになるくらいには使いこなせてないんだけど書く

パターンマッチ

最高of最高

Result型

コードを読む側、使う側としてResult型はとても便利。エラーを?でキャッチできるしこの関数にエラー処理が任されているんだなというのがひと目で分かる。 そもそも型というものがコールドリーディング時に便利。
たぶんOptionとResultは慣れると余計なエラーやNullの処理挟まなくて良くなるので便利そう。

ロスコンパイル

最終的に機械語になって人に配布できるというのがRubyから入るとかなり画期的に感じる。 一応このアプリもタグ付けしたらGithubActionで複数OSでバイナリをビルドしてzipにしてリリースするということができた。(linux環境だと何故かOpenSSLがないと言われてリリースビルドが通らない。libssl-devを直接入れても再現するので困ってる)

cargo

Elixirのmixと同じで、ライブラリやテストが言語に組み込まれているのもモダンな言語感があってよかった。リンターもしっかり搭載。

ビルド通ったときの安心感

僕はCとかの低級言語はなにも触った事ない。けれどよく未定義動作の処理に困る話は聞く。その中でRustでコンパイラ通るということはメモリを贅沢につかってこそすれ危険に利用してないことなので安心感がある。

俺は今Rustというかっこいい言語で開発しているという謎の興奮

これが9割

まとめ

Rust本当になにもわからん。でも実践Rust入門は良書です。