UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Rust】Rustの特徴について

はじめて触った言語はFortranで、先人が書いたコードをスパコンで動かすというようなことをしたことがある

そのあとCとC++も同じような感じでちょっとだけ触ったことがあるが、どちらもメモリを正しく管理することが難しいというか、あまり理解できぬままにJavaなどを触るようになった

それゆえメモリを意識して書く言語にはちょっと抵抗があったが、Rustを調べていくとCやC++同等の性能を持つが、CやC++よりもメモリ管理が安全で、並列処理もお得意な言語ということでちょっと興味がわいたので本を読んでみた

Rustの特徴

Rustの特徴的な機構として以下があるとのこと

  • 所有権(ownership)
  • 移動(move)
  • 借用(borrow)

これらはC、C++などで煩わしかったポインター利用のミスなどを起こさないように設計された新しいメモリ管理機構で、Javaなどではポインター利用のミスなどを起こさないようする作業をGCがやってくれていたが、そのGCも不要になるのがRustの評判の良いところっぽい

所有権と移動

本の所有権の章だけまとめてみた

本では所有権を理解するのに他の言語との違いを説明していた

Python

次のようなコードをPythonではどうメモリ上で表現されるか

s = ['udon', 'ramen', 'soba']
t = s
u = s

sに代入した後のプログラムの状態と、プログラムの実行が終了した時点での状態の図は以下のようになる
f:id:uggds:20210826220829p:plain:w600

Pyhonでは、すべてのPythonオブジェクトが現在そのオブジェクトを参照している数を数える参照カウントをもっているので、 代入した後は参照先のオブジェクトの参照カウントが増えるだけの代入操作になる

代入操作が安価というメリットがあるが、参照カウントの管理が複雑になるデメリットがある

C++

次のようなコードをC++ではどうメモリ上で表現されるか

using namespace std;
vector<string> s = { "udon", "ramen", "soba"};
vector<string> t = s;
vector<string> u = s;

sに代入した後のプログラムの状態と、プログラムの実行が終了した時点での状態の図は以下のようになる
f:id:uggds:20210826222022p:plain:w600

C++ではベクタを代入していくとベクタのコピーがつくられ、結果定に3つのベクタと9つの文字列が確保された状態になる

オブジェクトの参照元(所有者)が明確なのでメモリをいつ解放して良いかプログラムが決定しやすくなるメリットがあるが、無制限にメモリと計算時間を消費するデメリットがある

Rust

次のようなコードをRustではどうメモリ上で表現されるか

let s = vec!["udon".to_strin(), "ramen".to_string(), "soba".to_string()];
let t = s;
let u = s;

一見問題なさそうだが、そもそもこれはコンパイルエラーになる

sに代入した後のプログラムの状態と、次のtに代入した後のプログラムの状態の図は以下
f:id:uggds:20210826222853p:plain:w400

RustはC++と同様なツリー構造になっているが、値を代入すると代入元から代入先へ「所有権」が「移動」する

そして、もともと所有していた親は未初期化状態になるので、未初期化状態の値を使おうとしてエラーになる

このように、Rustはほとんどの型がオブジェクトの単一所有のルールをもつので、参照元のカウント管理をする必要もないし、コピーをつくる必要もないというのが他の言語にない特徴になっている模様

ちなみに、Pythonのように所有権を共有することもできるし(RcArcというのを使う)、C++のように子のコピーをもつようにすることもできる(cloneメソッドを使う)

まだまだわからないことはあるが、なんとなくメモリ管理が面白い言語だということがわかった