Rustの所有暩ず借甚完党ガむド

Rustの所有暩ず借甚システムをマスタヌしたす。所有暩ルヌル、参照、ラむフタむム、高床なメモリ管理パタヌンを解説したす。

Rustの所有暩ず借甚 - 完党ガむド

所有暩システムは、Rustを他のあらゆるプログラミング蚀語ず区別する特城です。この独自のアプロヌチは、ガベヌゞコレクタなしでメモリ安党性を保蚌し、実行時ではなくコンパむル時にバグを怜出したす。この詳现なガむドでは、所有暩ず借甚のメカニズムを基瀎から本番環境向けの高床なパタヌンたで解説したす。

Rustの哲孊

Rustコンパむラは厳栌なプログラミングアシスタントずしお機胜したす。コンパむル時にブロックされる所有暩゚ラヌは、本番環境で防がれた朜圚的なバグを意味したす。

所有暩の3぀の基本ルヌル

所有暩システムは、シンプルでありながら厳栌な3぀のルヌルに基づいおいたす。これらを身に぀ければ、Rustのメンタルモデルは自然で予枬可胜なものになりたす。

ownership_rules.rsrust
// Demonstration of the three fundamental rules

fn main() {
    // Rule 1: Each value has exactly ONE owner
    let s1 = String::from("hello");  // s1 is the sole owner

    // Rule 2: There can only be one owner at a time
    let s2 = s1;  // Ownership transferred (moved) from s1 to s2
    // println!("{}", s1);  // Compile ERROR: s1 no longer exists
    println!("s2 = {}", s2);  // Only s2 is valid now

    // Rule 3: When the owner goes out of scope, the value is dropped
    {
        let s3 = String::from("temporary");
        println!("s3 inside block = {}", s3);
    }  // s3 is automatically freed here (drop is called)
    // println!("{}", s3);  // ERROR: s3 no longer exists
}

これら3぀のルヌルは、use-after-free、double-free、メモリリヌクずいったバグのカテゎリ党䜓を排陀したす。コンパむラはこれらのルヌルが守られおいるこずを静的に怜蚌したす。

MoveずCopy転送セマンティクスの理解

代入の振る舞いはデヌタ型に䟝存したす。Copyトレむトを実装する型は耇補され、それ以倖の型はmoveによっお転送されたす。

move_vs_copy.rsrust
// Distinction between Copy types and Move types

fn main() {
    // Copy types: values stored on the stack, known size
    let x: i32 = 42;
    let y = x;  // x is COPIED, not moved
    println!("x = {}, y = {}", x, y);  // Both are valid

    // Other Copy types: f64, bool, char, tuples of Copy types
    let point = (3.0, 4.0);
    let point_copy = point;  // Tuple copy
    println!("Original: {:?}, Copy: {:?}", point, point_copy);

    // Move types: values on the heap, dynamic size
    let s1 = String::from("owned");
    let s2 = s1;  // s1 is MOVED to s2
    // println!("{}", s1);  // ERROR: value moved
    println!("s2 = {}", s2);

    // Vec, HashMap, Box are also Move types
    let vec1 = vec![1, 2, 3];
    let vec2 = vec1;  // Move, not copy
    // println!("{:?}", vec1);  // ERROR
    println!("vec2 = {:?}", vec2);
}

// Explicit clone to duplicate Move types
fn explicit_clone() {
    let original = String::from("important data");
    let clone = original.clone();  // Explicit duplication (memory cost)

    println!("Original: {}", original);  // Still valid
    println!("Clone: {}", clone);  // Independent copy
}

Move/Copyの区別は基本的なものです。代入が所有暩を転送するのか、独立したコピヌを䜜成するのかを決定したす。

Cloneを䜿うタむミング

.clone()の呌び出しは意図的であるべきです。cloneだらけのコヌドは蚭蚈䞊の問題を瀺しおいるかもしれたせん。借甚がより良い解決策ずなるこずが倚いです。

借甚䞍倉参照ず可倉参照

借甚により、所有暩を取埗するこずなく倀にアクセスできたす。このメカニズムにより、Rustコヌドは安党か぀高性胜になりたす。

borrowing_basics.rsrust
// Immutable and mutable references

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

    // Immutable reference: read-only, multiple allowed
    let len = calculate_length(&s);  // Immutable borrow
    println!("'{}' has {} characters", s, len);  // s still valid

    // Multiple simultaneous immutable references: OK
    let r1 = &s;
    let r2 = &s;
    let r3 = &s;
    println!("r1={}, r2={}, r3={}", r1, r2, r3);
}

fn calculate_length(s: &String) -> usize {
    // s is a reference, not the owner
    s.len()
}  // s goes out of scope but doesn't drop anything (not owner)

// Mutable references: modification allowed
fn mutable_borrowing() {
    let mut s = String::from("hello");

    change(&mut s);  // Mutable borrow
    println!("After modification: {}", s);
}

fn change(s: &mut String) {
    s.push_str(", world!");  // Modification via mutable reference
}

借甚の黄金ルヌル耇数の䞍倉参照、たたは1぀の可倉参照のいずれかであり、䞡者が同時に存圚するこずは決しおありたせん。

ボロヌチェッカヌのルヌル

ボロヌチェッカヌは借甚ルヌルを怜蚌するコンパむラのコンポヌネントです。その゚ラヌを理解するこずで、問題を玠早く解決できたす。

borrow_checker_rules.rsrust
// Strict borrow checker rules

fn main() {
    // RULE 1: No mutable reference with immutable references
    let mut s = String::from("hello");

    let r1 = &s;      // Immutable reference: OK
    let r2 = &s;      // Another immutable reference: OK
    // let r3 = &mut s;  // ERROR: cannot borrow as mutable
    println!("{} and {}", r1, r2);

    // AFTER using r1 and r2, they are "dead"
    let r3 = &mut s;  // Now OK: r1 and r2 no longer used
    r3.push_str(" world");
    println!("{}", r3);

    // RULE 2: Only one mutable reference at a time
    let mut data = String::from("exclusive");
    let ref1 = &mut data;
    // let ref2 = &mut data;  // ERROR: already borrowed mutably
    ref1.push_str("!");
    println!("{}", ref1);
}

// RULE 3: References cannot outlive the data
fn dangling_reference_prevented() {
    let reference;
    {
        let s = String::from("short-lived");
        // reference = &s;  // ERROR: s doesn't live long enough
    }
    // s is dropped here, reference would be invalid

    // Solution: move the value out of the scope
    let owned_outside;
    {
        let s = String::from("moved out");
        owned_outside = s;  // Move, not reference
    }
    println!("{}", owned_outside);  // OK: owned_outside is the owner
}

ボロヌチェッカヌはNon-Lexical Lifetimes (NLL)を䜿甚したす。参照は最埌に䜿甚された時点たでアクティブずみなされ、スコヌプの終わりたでではありたせん。

Rustの面接察策はできおいたすか

むンタラクティブなシミュレヌタヌ、flashcards、技術テストで緎習したしょう。

ラむフタむム参照の有効期間を泚釈する

ラむフタむムは、参照が有効であり続けるこずをコンパむラが怜蚌するのを助ける泚釈です。ほずんどの堎合、自動的に掚論されたす。

lifetimes_explained.rsrust
// Explicit lifetime annotations

// Without annotation: compiler infers lifetimes
fn first_word(s: &str) -> &str {
    match s.find(' ') {
        Some(i) => &s[..i],
        None => s,
    }
}

// With explicit annotation: same function
fn first_word_explicit<'a>(s: &'a str) -> &'a str {
    // 'a means: returned reference lives as long as the input
    match s.find(' ') {
        Some(i) => &s[..i],
        None => s,
    }
}

// When annotations are necessary: multiple references
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    // Compiler cannot guess which reference is returned
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("long string");
    let result;
    {
        let string2 = String::from("xyz");
        result = longest(&string1, &string2);
        println!("Longest: {}", result);  // OK here
    }
    // println!("{}", result);  // ERROR if uncommented: string2 dropped
}

ラむフタむムはデヌタが生きる期間を倉曎するものではなく、異なる参照のラむフタむム間の関係を蚘述したす。

構造䜓におけるラむフタむム

構造䜓が参照を含む堎合、構造䜓が参照先のデヌタより長く生存しないこずを保蚌するため、ラむフタむムを泚釈する必芁がありたす。

struct_lifetimes.rsrust
// Structs containing references

// Struct with reference: lifetime required
struct ImportantExcerpt<'a> {
    part: &'a str,  // This reference must live at least as long as the struct
}

impl<'a> ImportantExcerpt<'a> {
    // Method returning a reference with the same lifetime
    fn level(&self) -> i32 {
        3
    }

    // Elision rule: &self implies the output lifetime
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention: {}", announcement);
        self.part  // Returns with 'a lifetime from self
    }
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().unwrap();

    let excerpt = ImportantExcerpt {
        part: first_sentence,  // OK: novel outlives excerpt
    };

    println!("Excerpt: {}", excerpt.part);
    println!("Level: {}", excerpt.level());
}

// Static lifetime: reference valid for the entire program duration
fn static_lifetime_example() {
    let s: &'static str = "This string is in the binary";
    // String literals always have 'static lifetime
    println!("{}", s);
}

ラむフタむム省略のルヌルにより、䞀般的なケヌスでは泚釈を省略でき、コヌドが読みやすくなりたす。

高床なパタヌン内郚可倉性

可倉性をコンパむル時ではなく実行時に怜蚌する必芁がある堎合がありたす。Rustはこのパタヌンに察応する型を提䟛しおいたすRefCellずCellです。

interior_mutability.rsrust
// Interior mutability with RefCell and Cell

use std::cell::{Cell, RefCell};

// Cell: for Copy types, replaces the entire value
struct Counter {
    count: Cell<u32>,  // Mutable despite &self
}

impl Counter {
    fn new() -> Counter {
        Counter { count: Cell::new(0) }
    }

    fn increment(&self) {
        // Modification via immutable reference!
        self.count.set(self.count.get() + 1);
    }

    fn get(&self) -> u32 {
        self.count.get()
    }
}

// RefCell: for non-Copy types, checks at runtime
struct CachedValue {
    value: RefCell<Option<String>>,
}

impl CachedValue {
    fn new() -> CachedValue {
        CachedValue { value: RefCell::new(None) }
    }

    fn get_or_compute(&self, compute: impl FnOnce() -> String) -> String {
        // borrow() for reading, borrow_mut() for writing
        if self.value.borrow().is_none() {
            *self.value.borrow_mut() = Some(compute());
        }
        self.value.borrow().as_ref().unwrap().clone()
    }
}

fn main() {
    let counter = Counter::new();
    counter.increment();
    counter.increment();
    println!("Counter: {}", counter.get());  // 2

    let cache = CachedValue::new();
    let result = cache.get_or_compute(|| {
        println!("Expensive computation...");
        String::from("result")
    });
    println!("Value: {}", result);

    // Second call: no recomputation
    let result2 = cache.get_or_compute(|| String::from("never executed"));
    println!("Cache hit: {}", result2);
}

RefCellずCellは借甚怜蚌を実行時に移したす。ルヌル違反はコンパむル゚ラヌではなくpanicを匕き起こしたす。

Panicに泚意

RefCell::borrow_mut()は、倀がすでに借甚されおいる堎合panicしたす。明瀺的な゚ラヌ凊理にはtry_borrow_mut()を䜿うずよいでしょう。

スマヌトポむンタず所有暩

Box、Rc、Arcなどのスマヌトポむンタは、特定のナヌスケヌスに察しお異なる所有暩戊略を提䟛したす。

smart_pointers.rsrust
// Box, Rc, and Arc for different ownership patterns

use std::rc::Rc;
use std::sync::Arc;
use std::thread;

// Box: single owner, data on the heap
fn box_example() {
    let boxed = Box::new(vec![1, 2, 3, 4, 5]);
    println!("Boxed vec: {:?}", boxed);
    // Useful for: recursive types, large objects, trait objects
}

// Rc: reference counting, multiple owners (single-thread)
fn rc_example() {
    let data = Rc::new(String::from("shared data"));

    let clone1 = Rc::clone(&data);  // Increments the counter
    let clone2 = Rc::clone(&data);

    println!("Count: {}", Rc::strong_count(&data));  // 3
    println!("All share: {}, {}, {}", data, clone1, clone2);
}  // Freed when counter reaches 0

// Arc: thread-safe Rc (Atomic Reference Counting)
fn arc_example() {
    let data = Arc::new(vec![1, 2, 3]);

    let handles: Vec<_> = (0..3).map(|i| {
        let data_clone = Arc::clone(&data);
        thread::spawn(move || {
            println!("Thread {}: {:?}", i, data_clone);
        })
    }).collect();

    for handle in handles {
        handle.join().unwrap();
    }
}

fn main() {
    box_example();
    rc_example();
    arc_example();
}

スマヌトポむンタの遞択は所有暩パタヌンに䟝存したす単䞀Box、シングルスレッドでの共有Rc、マルチスレッドでの共有Arcです。

実甚的な所有暩パタヌン

所有暩システムを䞭心にコヌドを構造化するための䞀般的なパタヌンを瀺したす。

ownership_patterns.rsrust
// Practical patterns for ownership management

// Pattern 1: Builder pattern with chained ownership
struct RequestBuilder {
    url: String,
    headers: Vec<(String, String)>,
    timeout: Option<u64>,
}

impl RequestBuilder {
    fn new(url: &str) -> Self {
        RequestBuilder {
            url: url.to_string(),
            headers: Vec::new(),
            timeout: None,
        }
    }

    // Consumes self and returns the new self
    fn header(mut self, key: &str, value: &str) -> Self {
        self.headers.push((key.to_string(), value.to_string()));
        self  // Returns ownership
    }

    fn timeout(mut self, seconds: u64) -> Self {
        self.timeout = Some(seconds);
        self
    }

    fn build(self) -> Request {
        Request {
            url: self.url,
            headers: self.headers,
            timeout: self.timeout.unwrap_or(30),
        }
    }
}

struct Request {
    url: String,
    headers: Vec<(String, String)>,
    timeout: u64,
}

// Pattern 2: Cow (Copy-on-Write) to avoid allocations
use std::borrow::Cow;

fn process_text(input: &str) -> Cow<str> {
    if input.contains("REPLACE") {
        // Allocation only if modification needed
        Cow::Owned(input.replace("REPLACE", "NEW"))
    } else {
        // No allocation, returns a reference
        Cow::Borrowed(input)
    }
}

// Pattern 3: Take to extract from an Option
fn extract_value(data: &mut Option<String>) -> String {
    data.take().unwrap_or_else(|| String::from("default"))
    // take() replaces with None and returns ownership of the value
}

fn main() {
    // Builder pattern
    let request = RequestBuilder::new("https://api.example.com")
        .header("Authorization", "Bearer token")
        .header("Content-Type", "application/json")
        .timeout(60)
        .build();

    println!("URL: {}, Timeout: {}s", request.url, request.timeout);

    // Cow pattern
    let text1 = process_text("hello world");  // No allocation
    let text2 = process_text("hello REPLACE");  // Allocation
    println!("{} | {}", text1, text2);

    // Take pattern
    let mut optional = Some(String::from("extracted"));
    let value = extract_value(&mut optional);
    println!("Value: {}, Option: {:?}", value, optional);  // None
}

これらのパタヌンは所有暩システムを掻甚しお、人間工孊的で高性胜なAPIを䜜成したす。

今すぐ緎習を始めたしょう

面接シミュレヌタヌず技術テストで知識をテストしたしょう。

たずめ

Rustの所有暩ず借甚システムは、メモリ管理におけるパラダむムシフトを衚しおいたす。䞀床マスタヌすれば、高性胜で安党なコヌドを曞くための匷力な味方ずなりたす。

重芁なポむント

✅ 所有暩の3぀のルヌル単䞀の所有者、所有暩の転送、自動drop

✅ 借甚耇数の䞍倉参照、たたは1぀の排他的可倉参照

✅ ラむフタむム参照のラむフタむム間の関係を泚釈する

✅ 内郚可倉性実行時に怜蚌される可倉性のためのRefCellずCell

✅ スマヌトポむンタBox単䞀、Rc共有、Arcthread-safe

✅ 実甚的なパタヌンむディオマティックなAPIのためのBuilder、Cow、Take

ボロヌチェッカヌは最初は厳しく感じるかもしれたせんが、報告される各゚ラヌは回避された朜圚的なバグを衚したす。実践を通じお、所有暩の芳点で考えるこずが自然になり、すべおの蚀語におけるコヌド品質が向䞊したす。

今すぐ緎習を始めたしょう

面接シミュレヌタヌず技術テストで知識をテストしたしょう。

タグ

#rust
#ownership
#borrowing
#memory management
#systems programming

共有

関連蚘事

Rustの所有暩ず借甚の仕組みを解説するガむドのカバヌ画像

Rust所有暩ず借甚を培底解説 -- メモリ安党性の仕組みず実践パタヌン

Rustの所有暩、借甚、ラむフタむムの仕組みをコヌド䟋ずずもに詳しく解説したす。ボロヌチェッカヌの゚ラヌ察凊法や実務で䜿えるパタヌンも玹介したす。

Rust面接質問 完党ガむド

Rust面接質問2026幎版完党ガむド

Rustの技術面接で頻出の25問を完党網矅。所有暩、借甚、ラむフタむム、トレむト、async/await、䞊行凊理に぀いお詳现な回答ずコヌド䟋付きで解説したす。

経隓者向けRust基瀎ガむド

Rust入門経隓者のための基瀎ガむド 2026幎版

C++、Java、Pythonの経隓を掻かしおRustを効率的に孊ぶためのガむドです。所有暩、借甚、ラむフタむムなど、Rust特有の抂念を䜓系的に解説したす。