🦀

100日後にRustをちょっと知ってる人になる: [Day 10]所有権という考え方

2022/09/01に公開1

Day 10 のテーマ

Day 9 まで Rust 固有の言語仕様というよりも、全体概要や一般概念についてみてきました。
今日は、少し Rust 固有な起用である 所有権 (Ownership) について調べてみます。

Rust を学ぼうと思い始めた頃に、「所有権」という考え方があって、それが結構難しいというコメントをあちらこちらで見たことがあります。学び始めて 10日目の今日時点、その「所有権」というものがなんたるか、何もわかっていないので、今日はどんなものなのか学ぼうと思っています。

所有権

まず最初にいくつかの Rust について説明している書籍や Web サイトでの所有権の表し方について拾い上げてみます。

  • 安全にポインタを利用できるようにしているのが「所有権」であり「借用」です
  • 型関数がリソースを開放する権利
  • 変数を値に束縛すると、変数はその値の所有者であり、その値の所有権を持っている
  • 所有者は所有権を持つ者
  • 所有者は常に単一の変数
  • 値自身も他の値の所有者になれる

いくつかの所有権に関する説明を見ると、変数の関係であることが分かります。そして C/C++ にもある ポインタという考え方を安全に使用するための仕組みであることも分かりました。

所有権に関する原則をまとめると次の3つになるようです。

  1. 所有者と呼ばれる変数に対応する
  2. 所有者は常に単一
  3. 所有者がスコープから外れると値の破棄

変数とスコープ

所有権について理解するためには、変数とスコープの関係について知っておく必要がありそうです。

  • スコープ: 要素が有効になっているプログラムの範囲

以下のコード例をみてスコープについて理解します。

{                   // s は宣言されておらず、有効ではない
    les s = "Rust"  // s が有効になる
    fn do_something() {
        s
    }
}                   // s の有効区間が終了

つまり、変数が宣言されて値が割り当てられてスコープが有効になります。そして使われなくなる場所になる(スコープを抜ける)まで有効になっている、ということになっています。

以下のケースでスコープを見てみます。

fn main() {
    let x = "foo".to_string();  // x が foo の所有権をもつ
    some_method(x);             // x を引数として渡し、x の所有権を失う

fn some_method(arg: String) {
    println!("{}", arg);        // arg が foo の所有権をもつ
}                               // arg がスコープから外れ、foo が破棄される

エラーケースについて考えておきます。

let s1 = String::from("Hello, Rust!");  // s1 が所有権をもつ
let s2 = s1;                            // s1 の所有権が s2 に所有権が移る
println!("s1は{}です。", s1);            // s1 が所有権を持っていないためエラーになる
//println!("s2は{}です。", s2);          // s2 が所有権をもっているためこちらが正常動作する

Day 10 のまとめ

所有権に関して変数のスコープの観点や、受け渡しの観点で確認をしてみました。
なんとなく所有権の雰囲気が分かったような気はしますが、ポインタの考え方を含めてのメモリのアロケーションなどについてまで把握しておく必要があるかないのかなど、もう少し深堀りして考えてみようと思います。

GitHubで編集を提案

Discussion

bobbob

初めまして、
最近 Rust を始めた同士として参考させていただいております。
この記事についてちょっと気づいたことがあってコメントさせていただきます。
最初のスコープのコード例ですが、
ファンクションの中から外部のsをアクセスできないため、エラーになりますから、
訂正したほうがよろしいかと思います。

100日後にどうなるか、楽しみですね。