[Rustのはじめ方] Part9: 所有権の概念(move, copy)

Rust

Rustの世界へようこそ!今回はRustの最もユニークで重要な機能の一つである所有権について学びます。特に、値がどのように変数間で移動するのか、Move(ムーブ)Copy(コピー)の違いに焦点を当てていきましょう。

所有権は、Rustがガベージコレクタなしでメモリ安全性を保証するための仕組みです。最初は少し難しく感じるかもしれませんが、理解すれば安全で効率的なコードを書くための強力な武器になります💪

所有権のルール

Rustの所有権には、以下の3つの基本的なルールがあります。

  1. それぞれの値は、所有者と呼ばれる変数を持っています。
  2. 一度に存在できる所有者は、ただ1つだけです。
  3. 所有者がスコープ(変数が有効な範囲)から外れると、値は自動的に破棄(メモリ解放)されます。

これらのルールによって、メモリリークやダングリングポインタといった問題をコンパイル時に防ぐことができます。

Move(ムーブ) – 所有権の移動 🚚

Rustでは、多くの型で、値を別の変数に代入すると所有権が移動(Move)します。これは特に、ヒープ領域にデータを格納する型(例: String)で重要になります。

例を見てみましょう:

let s1 = String::from("hello"); // s1が"hello"の所有者
let s2 = s1;                  // s1の所有権がs2にMoveする

// println!("s1 is: {}", s1); // この行はコンパイルエラー! s1はもはや無効

上のコードでは、s1が持っていたString値の所有権がs2に移動しました。Moveが発生した後、元の変数s1は無効になり、アクセスしようとするとコンパイルエラーになります。これは、二重解放(同じメモリ領域を2回解放しようとすること)を防ぐためです。

Moveは、ヒープに割り当てられたデータの所有権を効率的に移転する方法です。データのコピーが発生しないため、パフォーマンス上の利点があります。

Copy(コピー) – 値の複製 🐑

一方、整数型 (i32, u64など)、ブール型 (bool)、浮動小数点数型 (f64)、文字型 (char) のような、サイズが既知でスタック上に完全に格納される型は、代入時に値がコピー(Copy)されます。

これらの型はCopyトレイトを実装しています。Copyトレイトが実装されている型では、代入後も元の変数は有効なままです。

例を見てみましょう:

let x = 5;    // xは5の所有者
let y = x;    // xの値がyにCopyされる

println!("x = {}, y = {}", x, y); // これはOK! xもyも有効

この場合、xの値5yにコピーされます。xは依然として有効であり、5という値を持っています。これは、スタック上のデータのコピーは非常に高速に行えるためです。

Copyトレイトを持つ型は、暗黙的にCloneトレイトも実装しています。Cloneは明示的に深いコピーを行うためのトレイトです。

MoveとCopyの挙動まとめ

挙動説明対象となる主な型代入後の元の変数
Move所有権が移動する。ヒープ上のデータのコピーは発生しない。String, Vec<T>, Box<T> など (Copyトレイトを実装していない型)無効
Copy値が複製される。スタック上のデータが対象。整数型 (i32, u64等), ブール型 (bool), 浮動小数点数型 (f32, f64), 文字型 (char), 要素がCopyなタプルなど (Copyトレイトを実装している型)有効

まとめ ✨

今回はRustの所有権の基本、特にMoveCopyの挙動について学びました。

  • Moveは所有権を移し、元の変数を無効にします(主にヒープ上のデータ)。
  • Copyは値を複製し、元の変数も有効なままです(スタック上のデータ、Copyトレイト実装型)。

所有権システムは、Rustがメモリ安全性をコンパイル時に保証するための核心的な仕組みです。この概念をしっかり理解することが、Rustプログラミングの第一歩となります。

次回は、所有権を移動させずに値を使いたい場合に役立つ「借用」について学んでいきましょう!➡️

コメント

タイトルとURLをコピーしました