何を隠そうこの私、はるか昔の転職前はCとC++を主戦場にしていましたが、転職後はRuby, Python, Golangあたりで生きてきました。あとSQLとクソJavaか。
自宅ではMacとRaspberry Piで動かしたいことも多いし、普通にdocker(つまりLinuxね)の中で動かしたいこともある…となるとGolangがベストかなぁと思っていたんです。
一方で、Golang(マルチプラットフォーム、シングルバイナリのデプロイ)に対抗しうる存在として、Rustという言語があります。手続き型でシステムプログラミング向けに使えて、割と独特の考え方で安全側に倒したもの…ということで、Golangにあるようなユルさがないので共通の住人は少ないという印象。似た感じだとJuliaだのNimなんかも悪くはないんでしょうけど。
で、私は最近Rustも使ってみてるんですよ。そして今後もちょくちょく使っていこうと思っているんですよ。
…ということで、ファーストインプレッションを以下に。
良いと思った点
- 性能が良い
- rustupが便利←pyenvみたいなやつ
- cargoが便利←pip, setup.py, twine, sphinx, etc…みたいなやつ
- cargoは本当に何かと気が利いている。cargo newでgit initまでやってくれたり
- cargo-editみたいなプラグインにも割と便利なものが多い
- crates.ioが便利←PyPI, readthedocsみたいなやつ
- コンパイラのチェックが強い。間違った書き方をするとコンパイルが通らないので実行する前に確実に分かる。エラーメッセージが割と親切
- structとメソッドの書き方とかは割とGolangに近くて覚えやすい
- OptionとかResultはGolangのerrorよりも好きかな
- あとmatchね
勉強すれば対応できそうな点
- let, struct, impl, trait
- セミコロンの有無による動作の違い
- mut指定
- unwrap()地獄
- lifetime
- move/borrow
- マクロ
- brew install rustは廃止した方がいいのでは? brew install rustup-init ; rustup-init が推奨。brew install rustだとrustfmtとかが入らないので割と面倒な話になる
- ビルドが遅いかも。Golangとかと比べての話。でかいプログラムは書いてないのでまだ分かんないけど、依存ライブラリのビルドとかを見ていてそう思った
- 結局みんなnightlyを使ってるんじゃないかという疑惑?
- だってstableやbetaはカバレッジもベンチマークも使えないんだもん
悪いと思った点
- 必須と思える機能が(stable/betaや標準に)ない
- ベンチマークとかプロファイルとかカバレッジツールとか
- いずれ解消するはずなので、あまり気にしてもしょうがないかも
- 直感に反して参照を返す必要があるstdのtrait
- Index/IndexMut ← set()/get()との対応がつけられねー
- Deref/DerefMut ←これはマジで意味わからん…dereferenceをオーバーライドするときにリファレンスを返さなきゃいけないなんて? それが役に立つのはどういう局面よ??
- 何を言っているかというと、例えばKVSとかでmapや配列のようなものを実装したとき、[]をオーバーライドするのが自然だと思うじゃないですか
- しかしIndexはget()の結果ではなく参照を返さなければならない。[]=の場合もIndexMutは引数をもらってset()を呼び出すのではなく参照を返す。呼び出し元で代入するまではset()できない
- そんで代入を横取りしようとdereferenceをオーバーライドしようと思ったとしても、それも参照を返さなきゃならないので、詰む
- だから既存KVSのバインディングを見ても、誰も[]や[]=をオーバーライドしていない模様
- そもそもメソッドがリファレンスを返すのが難しい
- cannot return reference to local variable
- IteratorとIntoIterator
- 違いがあるのは分かったけど、両立させる必要があるかどうかは…どっちかだけで良かったんじゃ?
- イテレータを使うとmoveされてしまうので、ループを抜けた後にイテレータの状態を参照できない(※)
- reflectがない(?)
- reqwestがPythonのrequestsに相当するのかな? プロキシを環境変数やOS設定から自動設定してくれないので、プロキシの奥にいる「普通の」組織に属するユーザには使いにくい
※ イテレータを使うとmoveされる、は次のようなコードです。forを回して抜けた後に参照できない。Rangeはいいとしても、自分で書いたイテレータに関してもこうなので、、、途中でbreakで抜けて止まった場所を後から見る、みたいなこともできない。もちろんfor i in it.clone()みたいにコピーすればコンパイルは通るけど、用は足せない。
let it = 0..5; println!("it={:?}", it); // ←これはOK for i in it { println!("i={}", i); } println!("it={:?}", it); // ←これがコンパイルエラーになる