0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「Rustの基礎を理解:変数からライフタイムまで」

Last updated at Posted at 2025-08-11

Rustの概要

  • 目的 : 高速・安全・並行処理に強いプログラム言語
  • 特徴
    • メモリ安全、ガーベージコレクタなしで安全性を保証(コンパイル時チェック)
    • ゼロコスト抽象化 : 高レベルの構文でも低レベルな処理速度
    • 所有権システム : ポインタの安全性やランタイムをコンパイル時に管理
    • マルチスレッド安全性 : デーテ競合をコンパイル時に防ぐ

Rustの考え方

Rustの根本的な考え方は「安全性と効率は両立できる」というもの。
そのために以下の仕組みがある

  1. 所有権
    • 変数には「所有権」が一つだけ存在
    • 所有者がスコープを抜けると、そのデータは自動で破棄される
  2. 借用
    • 参照(&)で一時的に借りることができる
    • 読み取り専用は複数OK、書き込みは一つだけ
  3. ライフタイム
    • 参照が無効になるタイミングをコンパイル時に保証

これらにより、Cなどでありがちなメモリ破壊やダングリングポインタを防ぐ。

基本的な使い方

rustは下記コマンドを使用してインストールを実施する

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

インストール後、次のコマンドでシェルにPATHを読み込ませる

. "$HOME/.cargo/env"
# プロジェクト作成
cargo new hello_rust

reating binary (application) `hello_rust` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

cd hello_rust

# 実行
cargo run

   Compiling hello_rust v0.1.0 (/home/yusuke/project/rust/hello_rust)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
     Running `target/debug/hello_rust`
Hello, world!

変数の扱い方

  1. 基本構文

    let x = 5;
    
    let x: i32 = 5; // 明示的に型指定
    
    • let で変数宣言
    • デフォルトでは不変
    • 型はコンパイラが推論してくれる(必要なら明示できる)
      • 型を間違えてもコンパイル時に検出できる
      • パフォーマンス最適化(適切なビット幅を選べる)
      • API や関数で意図を明確にできる
    型名 ビット幅 符号 範囲(例)
    i8 8 符号付き -128 ~ 127
    u8 8 符号なし 0 ~ 255
    i32 32 符号付き 約 -21億 ~ +21億
    u32 32 符号なし 0 ~ 約42億
    i64 64 符号付き もっと広い
    u64 64 符号なし もっと広い
  2. 可変変数
    デフォルトでは不変なので、値を変えたい場合は、mutを付ける

    let mut count = 0;
    count = 10; // OK
    
    • 不変と可変の違い
      • 不変: 値を再代入できない(コンパイルエラーになる)
      • 可変: 再代入できるが、所有権や借用ルールは守る必要がある
  3. 変数のシャドーイング

    • let 変数名 = 値 を同じ名前で書き直すと古い変数は破棄され、新しい変数が作られる
    • 変数の「再代入」ではなく「再宣言」
    • 特徴
      • mut なしで値を変更できる(実際は新しい変数)
      • 型の変更も可能
      • 古い変数は完全に消えるため、参照や値の衝突が起きない
      • 安全性を損なわない理由
        • 古い変数は「死んで」おり、生きたままの変更ではないため、Rust の不変ルールと矛盾しない
    mut(可変) シャドーイング
    実態 同じ変数の中身を変更する 別の新しい変数を作る
    型の変更 不可 可能
    安全性への影響 参照がある場合は制約が厳しい 古い変数は破棄されるので安全
    let x = 5;     // 不変
    let x = x + 1; // 新しい変数で上書き(再宣言)
    println!("{}", x); // 6
    
  4. 定数

    const PI: f64 = 3.14159;
    
    • const キーワードで宣言

    • 型指定(: f64 の部分)が必須

    • 値はコンパイル時に決まっている必要がある (絶対に不変)

      • 実行中はもちろん、シャドーイングや再代入も不可能

        const TAX: f64 = 0.1;
        
        fn main() {
            const TAX: f64 = 0.08; // ❌ エラー
            println!("{}", TAX);
        }
        
        
    • 命名規則としては大文字スネークケース(MAX_POINTS など)が慣例

所有権

  1. 所有権の概要

    Rust ではすべての値には「所有者(owner)」がただ1つだけ存在し、
    その所有者が「アクセス権」と「メモリ管理の責任」を持つ。

  2. 所有権のルール

    • すべての値には所有者が1人だけ
    • 所有者がスコープを抜けたら値は破棄され、メモリも自動解放
    • 所有権は移動(ムーブ)できる
  3. 所有権が管理しているもの

    • アクセス権限:その変数の読み書きができる唯一の権利
    • メモリ領域の責任:スコープ終了時に安全に解放する責任
  4. 所有権の動き

    • ムーブ(Move)
    fn print_string(s: String) {
        println!("{}", s);
        }
    
    fn main() {
        let s1 = String::from("hello");
        print_string(s1); // 所有権が関数引数にムーブ
        println!("{}", s1); // ❌ s1はもう使えない
        }
    
    • コピー
    let x = 5;
    let y = x; // 値がコピーされる(整数型などスタックだけの型)
    println!("{}", x); // OK
    
    • クローン
    let s1 = String::from("hello");
    let s2 = s1.clone(); // ヒープの中身も複製
    println!("{}, {}", s1, s2); // OK
    
  5. 所有権のメリット

    • メモリ安全
      • 二重解放なし
      • ダングリングポインタなし
    • ガーベジコレクタ不要
      • 実行時コストゼロ
      • 解放タイミングが予測可能
    • データ競合防止
      • マルチスレッドでも安全
  6. まとめ

    • 所有権は「変数への唯一のアクセス権+そのメモリの片付け責任」。
    • スコープ終了と同時に権限も責任も消え、メモリは自動で解放される。

借用

  1. 借用の概要
    • 所有権は移動させずに、変数を一時的に使用されてもらうこと
    • 所有者は変わらないので、借用が終わったら元の変数をそのまま使える
    • & を付けて参照を作る

2. 不変借用

  • 特徴

    • 複数同時に借用できる(読み専用なので安全)
    • 借用先では読み込みはできるが書き込みはできない
    fn main() {
        let s = String::from("hello");
    
        print_string(&s); // sを不変で借用
        println!("{}", s); // 借用後もsは使える
    }
    
    fn print_string(s: &String) {
        println!("{}", s);
    }
    

3. 可変借用

  • 特徴

    • 1つのデータに対して同時に1つだけ可変借用が可能
    • 可変借用中は不変借用も禁止(データ競合防止)
    fn main() {
        let mut s = String::from("hello");
    
        change_string(&mut s); // 可変で借用
        println!("{}", s); // 借用後もsは使える
    }
    
    fn change_string(s: &mut String) {
        s.push_str(", world");
    }
    

4. 借用のメリット

  • 所有権を移動させないので、元の変数を借用後も使える
  • 安全にデータを共有できる(コンパイル時にデータ競合チェック)
  • 関数間のデータ受け渡しが効率的(コピー不要)

5. 所有権と借用の違い

所有権 借用
データの責任ごと渡す アクセス権だけ渡す
ムーブ後は元の変数は使えない 借用後も元の変数を使える
解放の責任も移動 解放の責任は元の所有者のまま

ライフタイム

  1. ライフタイムの概念

    • 参照が有効でいられる期間(寿命) を表す概念。
  2. なぜ必要か

    fn main() {
    let r;
    {
        let x = 5;
        r = &x; // ❌ xはこのブロックを抜けると消える
    }
    println!("{}", r); // 参照切れ(Cなら未定義動作)
    }
    

    Rustではコンパイルエラーになる:

    error[E0597]: `x` does not live long enough
    

    理由:x のライフタイムが r より短いので、r は無効なメモリを指すことになる。

  3. ライフタイムの基本ルール

    • 借用は元の変数が有効な間だけ生きられる
    • 元の変数がスコープを抜けたら、その参照も同時に死ぬ
    • コンパイラは「すべての参照が有効なメモリを指している」ことを保証する
  4. まとめ

    • ライフタイムは参照の有効期間
    • 所有者より長生きする参照は作れない
    • コンパイル時に参照切れを完全に防ぐ
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?