Rustの所有権について学習をしてみる

※本ブログはアフィリエイトで収益を得ています

はじめに

過去に少しだけRustの学習をしていました。今回改めてRustの学習を始めるにあたり、Rustの所有権について学習をしていきます。

所有権とは

Rustの所有権とは、メモリの安全性を保証するための概念です。Rustの所有権には以下の3つのルールがあります。

  1. 各値は、その値の所有者という変数を持っています。
  2. 一度に一つの変数のみが値の所有者であることができます。
  3. 所有者がスコープから外れると、値は破棄されます。

なるほど、日本語としては理解しましたが、実際にコードを書いてみないと理解できない部分もあると思います。そこでコードを書いていきます。

所有権の移動

  1. 一度に一つの変数のみが値の所有者であることができます。

の部分について確認をしていきます。下記は変数s1をs2に代入したコードです。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;

    println!("{}, world!", s1); // これはエラーになる
}

ビルドすると下記の通りエラーが出ました。これは文字列Helloという値の所有権がs1→s2となったためエラーとなるようです。

error[E0382]: borrow of moved value: `s1`
 --> src/main.rs:5:28
  |
2 |     let s1 = String::from("hello");
  |         -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 |     let s2 = s1;
  |              -- value moved here
4 |
5 |     println!("{}, world!", s1); // これはエラーになる
  |                            ^^ value borrowed here after move
  |
  = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
  |
3 |     let s2 = s1.clone();
  |                ++++++++

For more information about this error, try `rustc --explain E0382`.
warning: `Ownership` (bin "Ownership") generated 1 warning
error: could not compile `Ownership` (bin "Ownership") due to previous error; 1 warning emitted

所有権のクローン

それでは所有権を失くすことなく、他の変数へ代入をするのはどうすればいいのか。そこで使用するのが「所有権のクローン」です。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();

    println!("s1 = {}, s2 = {}", s1, s2);
}

ビルド・実行をすると期待通りの結果が得られました。

warning: crate `Ownership` should have a snake case name
  |
  = help: convert the identifier to snake case: `ownership`
  = note: `#[warn(non_snake_case)]` on by default

warning: `Ownership` (bin "Ownership") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 4.03s
     Running `target/debug/Ownership`
s1 = hello, s2 = hello

所有権の破棄

  1. 所有者がスコープから外れると、値は破棄されます。

次に上記のルールについて確認をしていきます。

下記のコードを実行すると、変数s1のスコープが外れたため、s1の値は破棄されることになります。

fn main() {
    {
        let s = String::from("hello"); // sが"hello"を所有
        println!("{}", s); // sは使用可能
    } // sのスコープの終わり。sはここで破棄される。

    println!("{}", s); // sはすでに破棄されているため、使用不可能
}

実際に下記の通りエラーが出ました。

error[E0425]: cannot find value `s` in this scope
 --> src/main.rs:7:20
  |
7 |     println!("{}", s); // sはすでに破棄されているため、使用不可能
  |                    ^ not found in this scope

For more information about this error, try `rustc --explain E0425`.
error: could not compile `Ownership` (bin "Ownership") due to previous error

最後に

今回はRustの所有権について学習を行いました。次回は参照について学習を行う予定です。