// article
Rust の所有権を深掘り - メモリ安全性の秘密.
Rust の所有権を深掘り
Rust の最大の特徴は、コンパイル時にメモリ安全性を保証する所有権システムです。本記事では、所有権(Ownership)と借用(Borrowing)の関係性を詳しく探ります。
所有権とは何か
fn main() {
let s1 = String::from("hello");
let s2 = s1; // 所有権がs1からs2に移動
// println!("{}", s1);
println!("{}", s2);
}
借用(Borrowing)による参照
所有権を譲渡せずに値を使いたい場合、借用を使用します:
fn main() {
let s = String::from("hello");
let len = calculate_length(&s); // 参照を渡す
println!("'{}' の長さは {}", s, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
ライフタイム(Lifetime) アノテーション
複数の参照が関わるとき、コンパイラは各参照の有効期間を理解する必要があります:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
ライフタイムのビジュアライゼーション
x: |-------- lives until here
y: |------ lives until here
output: |---- result must be validライフタイムアノテーション 'a により、「戻り値は両方の入力と同じ期間生存する」ことをコンパイラに伝えます。
Move Semantics と Copy Semantics
スタック上に完全に収まる型(i32, bool, (i32, f64) など)は Copy セマンティクスで、代入時に自動的にコピーされます。
実践的なパターン
struct User {
name: String,
email: String,
}
fn create_user(name: String, email: String) -> User {
User { name, email } // 所有権を移動してUserを返す
}
fn main() {
let user = create_user(
String::from("Alice"),
String::from("alice@example.com")
);
// userは所有権を持っている
println!("{}", user.name);
}
所有権システムが最初は複雑に見えるかもしれませんが、一度理解すれば Rust のコード設計がいかにシンプルで安全かが見えてきます。