🦀

【Rust】始めてみて、つまづいたことなど

2022/02/11に公開

Rustが良いらしいですね。
以前の自分の知識でいくと低級言語と言えばC/C++でしたが、最近はTwitterとかでRustの話題をよく聞くようになり、興味を持ちました。
以下は理解不足を晒しているだけですが、実際に触ってみた感想です。

やってみたこと

Rustの日本語版ドキュメントを参照して、環境のインストール、Hello World、数あてゲーム。
https://doc.rust-jp.rs/book-ja/

その後、リバーシ(両者ともに手入力、CLIで表示)の作成。

つまづいたこと

C/C++を何年も触っていなかったのでポインタ関係の扱いはどうだったっけ、と思い出しながらでしたが、いくつかつまづいたことがありました。
それぞれまだ理解が追いついていないので、もっと馴れ親しんで納得するまで習得したいところです。

文字列の扱い

チュートリアルの数あてゲームでも、文字列の扱いは&str型とString構造体との両方が使われていましたが、この両者の関係がよくわかっていません。
具体的なことではStringの文字列からcharを取りだす方法や、文字列を定数文字列と比較してイコール判定する方法などを悩みました。
とりあえずやりたいことを実装はできたものの、Stringが何者なのかまだよく理解できていません。

整数型の扱い

メモリけちけち精神でu8とか使っていたのですが、この変数を配列のインデックスに使おうとするとusize型じゃないとだめですよと言われました。
結局arr[usize::from(i)]のようなことをやったりしたわけですが、あまり嬉しい感じはしません。
インデックスの型が何であるかという問題は値が配列の長さの範囲内かという問題とは別だと思いますが、無理やり型を変換するのではあまり意味がないのでどう考えるべきなのでしょうか。
また、一時的に負になる可能性ある変数をi8型で使っていて範囲の判定はコード内で済ませているときに、arr[usize::from(i as u8)]なんて書いたりしていて、これだと型制限の恩恵が少ないし可読性が落ちている気がしています。

所有権

一番悩んだのがこれでした。
特に構造体のメソッドでselfを引数に持たせていてエラーになって悩まされました。
ワークアラウンドとしては引数のselfを&selfに変更して所有権を奪わないようにすると大丈夫だったのですが、これまでやってきた言語で所有権を扱ったことがないのでコーディングの際にどう意識すべきかというのがまだピンと来ていません。
メソッドが終了しても呼び出し元に所有権が戻らないというところに不便さを感じました。
オブジェクトが破棄されるタイミングに関わっているので、関数内で破棄されるべきもの以外は基本参照渡しということでしょうか。

struct Test {
    a: usize,
    b: usize,
}
impl Test {
    fn is_ok(self) -> bool { // fix "self" to "&self"
        self.b > self.a
    }
    fn increment(mut self) { // fix "mut self" to "&mut self"
        self.a += 1;
    }
}

fn main() {
    let mut t = Test { a: 1, b: 4 };
    if t.is_ok() { // `t` moved due to this method call
        t.increment(); // value used here after move
    }
    println!("a: {}, b: {}", t.a, t.b);
}

試してみたの感触

C/C++の欠点を克服するためにメモリ安全を志向しているというのがよく感じられました。
また文法的なストレスも少なく、とても良い印象です。

上記の躓きなどは自分の理解不足であって言語の問題ではないと思うので、できれば今後もこのRustを使っていきたいと思いました。

Discussion