はじめに
この記事はRust言語の勉強をしている人が必ずと言っても過言ではないRust言語特有の「所有権」についてを初心者向けにゆるくまとめた記事です。雰囲気を理解できていただければ嬉しいです。
Rust言語とは
Rust(ラスト)は、性能、メモリ安全性、安全な並行性を目指して設計されたマルチパラダイムのプログラミング言語である。C言語、C++に代わるシステムプログラミング言語を目指しており、構文的にはC++に似ているが、「ボローチェッカー(borrow checker)」で参照の有効性を検証することによってメモリ安全性を保証できる。Rustはガベージコレクションなしでのメモリ安全性を達成しており、必要な場面で参照カウントを使うこともできる
ー wikipedia Rust (プログラミング言語)
Rust言語は簡単に言うと
- 速い
- 安全
- メモリ安全
この3つを兼ね備えた言語になります。
この3つのうち「安全」を支えている概念が「所有権」になります。
今回はその所有権について簡単にまとめた記事になります。
所有権とは
多くの言語では大抵、変数から変数へ値を渡すときにはコピーが扱われていますが
Rust言語ではそれに加えて、所有権とムーブという概念でこの部分を制御しています。
Rustでは変数一つ一つに「持ち主」がいます。その持ち主がデータの所有権を持つことで操作できるようになります。
なぜ、そんな仕組みがあるのかというと、
他の言語では、
- 使っちゃいけないメモリを使ってしまった
- もう消えているはずのデータを参照してしまった
というような時々発生してしまう事故をコンパイル時点で止めるために、所有権という仕組みを使っています。
では、簡単な例から具体的に見てみます。
let s = "hello";
このコードでは"hello"という文字列データの所有権を変数's'(持ち主)が持つという関係になっています。
所有権が移動する
Rustでは、変数から変数へ値を渡すときに所有権が移動することがあります。
これを ムーブ(move) と呼びます。
例えば、次のようなコードを見てみます。
let s1 = String::from("hello");
let s2 = s1;
一見すると、s1をs2に代入しただけのように見えますが、この時点で"hello"というデータの所有権が s1 から s2 に移動しています。
つまり、
s2 → 持ち主
s1 → もう持ち主ではない
という状態になります。
ムーブの後は元の変数が使えない
先ほどのコードに追加するとどうなるでしょう。
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s1);
結果はコンパイルエラーになります。
理由は簡単で、s1はもう"hello"の持ち主ではないからです。
Rustは 持ち主ではない人がデータを扱うのはダメというルールを守ります。
これも「安全」のための仕組みなのです。
なぜこんなにも制限するのか
もし、s1もs2も同じデータの所有権を持っていたら、
- どちらが先にデータを操作するかわからない
- 解放されたデータを参照してしまう、書き換えてしまう可能性がある
という事故をコンパイルするときに防ぐため、ルールを徹底しています。
まとめ
今回は所有権とその特性について
- 変数(持ち主)とデータの関係
- 所有権はムーブされる
のようなものがあると雰囲気で理解できたと思います。
そして、Rustの安全性についての理由もわかったと思います。
終わりに
今回はRustでつまずきがちな所有権の入り口だけ扱いました。
この後には
- clone
- 借用(参照)
- 可変借用
- ライフタイム
等のような概念が続きますがすべて所有権がまとわりつきます。そのための土台となるような記事になればうれしいです。