# Rust入門:経験者のための基礎ガイド 2026年版 > C++、Java、Pythonの経験を活かしてRustを効率的に学ぶためのガイドです。所有権、借用、ライフタイムなど、Rust特有の概念を体系的に解説します。 - Published: 2026-01-09 - Updated: 2026-04-01 - Author: Anthony Fillion-Maillet - Tags: rust, systems programming, ownership, memory safety, performance - Reading time: 14 min --- Rustは年々採用が拡大しており、コンパイル時にメモリ安全性を保証しながらC++と同等のパフォーマンスを発揮し、モダンなエコシステムを備えた言語として注目されています。C++、Java、Pythonなどの経験がある開発者にとって、Rustの学習は最初こそ戸惑いがありますが、基本概念を理解すれば驚くほど直感的になります。 > **2026年、なぜRustなのか** > > RustはStack Overflowで8年連続「最も愛されている言語」に選ばれています。Microsoft、Google、Amazon、Metaがクリティカルなコンポーネントに採用しており、ガベージコレクターなしでメモリ安全性を実現する唯一の主要言語です。 ## Rust開発環境のセットアップ Rustのコーディングを始める前に、公式のバージョン管理ツールであるrustupを使ってインストールを行います。 ```bash # install.sh # Install Rust via rustup (macOS, Linux) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Verify installation rustc --version cargo --version ``` CargoはRustのパッケージマネージャーであり、ビルドツールでもあります。npm、Maven、Makeの機能を一つの統合ツールにまとめた存在です。 ```bash # project-setup.sh # Create a new project cargo new my_project cd my_project # Generated structure: # my_project/ # ├── Cargo.toml # Manifest (like package.json) # └── src/ # └── main.rs # Entry point # Essential commands cargo build # Compile the project cargo run # Compile and run cargo test # Run tests cargo check # Check without building (faster) ``` ## 変数とデフォルトの不変性 Rustは一般的な言語とは逆の発想を取っています。変数は**デフォルトで不変(イミュータブル)**です。この設計により、可変性について明示的に考えることを強制し、多くのバグを未然に防ぎます。 ```rust // variables.rs fn main() { // Immutable by default let x = 5; // x = 6; // Compile error! // Explicitly mutable variable let mut y = 5; y = 6; // OK // Shadowing: redeclaration in the same scope let x = x + 1; // Creates a new variable x let x = x * 2; // x is now 12 // Shadowing also allows changing the type let spaces = " "; // &str let spaces = spaces.len(); // usize } ``` > **シャドーイングとミュータビリティの違い** > > シャドーイングは新しい変数を作成するのに対し、`mut`は既存の値を変更します。シャドーイングを使えば、明確な名前を保ちながら値を変換できます。 ## 基本データ型 Rustは強力な型推論を備えた静的型付け言語です。ここでは知っておくべき基本的なプリミティブ型を紹介します。 ```rust // types.rs fn main() { // Signed integers: i8, i16, i32, i64, i128, isize let age: i32 = 30; // Unsigned integers: u8, u16, u32, u64, u128, usize let count: u64 = 1_000_000; // Underscores for readability // Floats: f32, f64 (default) let pi: f64 = 3.14159; // Boolean let active: bool = true; // Unicode character (4 bytes) let emoji: char = '🦀'; // Tuple: fixed collection of different types let person: (String, i32) = (String::from("Alice"), 28); let (name, age) = person; // Destructuring // Array: fixed size, same type let numbers: [i32; 5] = [1, 2, 3, 4, 5]; let first = numbers[0]; // Slice: view into a portion of data let slice: &[i32] = &numbers[1..4]; // [2, 3, 4] } ``` ## 所有権:Rustの革新的コンセプト 所有権(Ownership)はRust最大のイノベーションです。ガベージコレクターなしでメモリ安全性を保証する仕組みであり、初期の学習コストはかかりますが、その見返りは非常に大きいです。 ### 所有権の3つのルール ```rust // ownership.rs fn main() { // Rule 1: Each value has a single owner let s1 = String::from("hello"); // Rule 2: When the owner goes out of scope, the value is freed { let s2 = String::from("world"); // s2 is valid here } // s2 is dropped, no longer accessible // Rule 3: Only one ownership at a time (move) let s3 = s1; // s1 is MOVED to s3 // println!("{}", s1); // Error: s1 is no longer valid! println!("{}", s3); // OK: s3 is the owner } ``` ### ムーブとクローン ```rust // move_clone.rs fn main() { // Simple types (stack): automatic Copy let x = 5; let y = x; // Copy, not move println!("x = {}, y = {}", x, y); // Both are valid // Complex types (heap): Move by default let s1 = String::from("hello"); let s2 = s1; // Move // s1 is no longer usable // Explicit clone to duplicate let s3 = String::from("world"); let s4 = s3.clone(); // Deep copy println!("s3 = {}, s4 = {}", s3, s4); // Both valid } ``` > **ムーブと関数呼び出し** > > 値を関数に渡すと所有権が移動します。関数が所有者となり、呼び出し後はその値にアクセスできなくなります。戻り値として返さない限り、元のスコープでは使用できません。 ```rust // ownership_functions.rs fn main() { let s = String::from("hello"); takes_ownership(s); // println!("{}", s); // Error: s has been moved let x = 5; makes_copy(x); println!("{}", x); // OK: i32 implements Copy // To regain ownership, return the value let s2 = String::from("hello"); let s3 = takes_and_gives_back(s2); println!("{}", s3); // OK } fn takes_ownership(s: String) { println!("{}", s); } // s is dropped here fn makes_copy(x: i32) { println!("{}", x); } fn takes_and_gives_back(s: String) -> String { s // Returns ownership } ``` ## 借用:所有権を移さない参照 借用(Borrowing)を使えば、所有権を移動せずに値を利用できます。Rustで最も頻繁に使われるメカニズムです。 ```rust // borrowing.rs fn main() { let s1 = String::from("hello"); // Immutable reference: read-only let len = calculate_length(&s1); println!("Length of '{}': {}", s1, len); // s1 still valid // Mutable reference: modification allowed let mut s2 = String::from("hello"); change(&mut s2); println!("{}", s2); // "hello, world" } fn calculate_length(s: &String) -> usize { s.len() } // s goes out of scope but doesn't drop (it's a reference) fn change(s: &mut String) { s.push_str(", world"); } ``` ### 借用のルール ```rust // borrowing_rules.rs fn main() { let mut s = String::from("hello"); // Rule 1: Multiple immutable references simultaneously OK let r1 = &s; let r2 = &s; println!("{} and {}", r1, r2); // Rule 2: ONLY ONE mutable reference at a time let r3 = &mut s; // let r4 = &mut s; // Error: already borrowed mutably println!("{}", r3); // Rule 3: No mutable ref if immutable ref exists let r5 = &s; // let r6 = &mut s; // Error: r5 is still active println!("{}", r5); // Once r5 is used for the last time, mutable borrow is allowed let r7 = &mut s; // OK: r5 is no longer used after this r7.push_str("!"); } ``` ## ライフタイム:参照の有効性を保証する仕組み ライフタイムは参照が有効であり続けることを保証します。コンパイラが自動的に推論する場合がほとんどですが、明示的なアノテーションが必要になるケースもあります。 ```rust // lifetimes_basic.rs // Classic error: reference to freed data // fn dangling() -> &String { // let s = String::from("hello"); // &s // Error: s will be dropped, invalid reference! // } // Solution: return the owned value fn no_dangle() -> String { let s = String::from("hello"); s // Ownership transferred, no problem } ``` ### ライフタイムアノテーション ```rust // lifetimes_annotation.rs // The compiler can't figure out which reference will be returned // fn longest(x: &str, y: &str) -> &str { ... } // Error! // Explicit annotation: return lives as long as BOTH x AND y fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { 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: string2 dropped } ``` > **ライフタイムの省略規則** > > Rustにはライフタイムの省略規則(Elision Rules)があり、単純なケースではアノテーションを省略できます。初学者の場合、コンパイラのエラーメッセージに従うだけで十分対応可能です。 ## 構造体とメソッドの実装 構造体(Struct)はRustにおけるカスタム型の基本構成要素です。 ```rust // structs.rs // Struct definition #[derive(Debug)] // Enables printing with {:?} struct User { username: String, email: String, active: bool, sign_in_count: u64, } // Implementation block for methods impl User { // Constructor (convention: fn new or descriptive name) fn new(username: String, email: String) -> Self { Self { username, email, active: true, sign_in_count: 1, } } // Method: takes &self (reference to instance) fn is_active(&self) -> bool { self.active } // Method with mutation: takes &mut self fn deactivate(&mut self) { self.active = false; } // Method consuming self (rare) fn into_username(self) -> String { self.username } } fn main() { let mut user = User::new( String::from("alice"), String::from("alice@example.com"), ); println!("Active: {}", user.is_active()); user.deactivate(); println!("Active: {}", user.is_active()); // Debug print println!("{:?}", user); } ``` ## 列挙型とパターンマッチング Rustの列挙型(Enum)は、多くの言語のenumよりも遥かに強力です。各バリアントがデータを持つことができます。 ```rust // enums.rs // Simple enum enum Direction { North, South, East, West, } // Enum with data (algebraic data type) enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(u8, u8, u8), } impl Message { fn process(&self) { match self { Message::Quit => println!("Quitting"), Message::Move { x, y } => println!("Moving to ({}, {})", x, y), Message::Write(text) => println!("Writing: {}", text), Message::ChangeColor(r, g, b) => { println!("Color: rgb({}, {}, {})", r, g, b) } } } } fn main() { let msg = Message::Move { x: 10, y: 20 }; msg.process(); let msg2 = Message::Write(String::from("Hello Rust!")); msg2.process(); } ``` ### OptionとResult:エラーハンドリングの基礎 ```rust // option_result.rs use std::fs::File; use std::io::{self, Read}; fn main() { // Option: present or absent value (replaces null) let numbers = vec![1, 2, 3]; let first: Option<&i32> = numbers.first(); match first { Some(n) => println!("First: {}", n), None => println!("Empty list"), } // Utility methods let value = first.unwrap_or(&0); let doubled = first.map(|n| n * 2); // Result: success or error let result = read_file("config.txt"); match result { Ok(content) => println!("Content: {}", content), Err(e) => println!("Error: {}", e), } } fn read_file(path: &str) -> Result { let mut file = File::open(path)?; // ? propagates the error let mut content = String::new(); file.read_to_string(&mut content)?; Ok(content) } ``` > **?演算子について** > > `?`演算子はエラー伝播のためのシンタックスシュガーです。Resultが`Err`の場合は自動的にエラーを返し、`Ok`の場合はその中身を取り出します。 ## トレイト:Rustにおけるポリモーフィズム トレイトは共通の振る舞いを定義するもので、Javaのインターフェースやswiftのプロトコルに相当します。 ```rust // traits.rs // Trait definition trait Summary { fn summarize(&self) -> String; // Method with default implementation fn preview(&self) -> String { format!("{}...", &self.summarize()[..50.min(self.summarize().len())]) } } struct Article { title: String, author: String, content: String, } struct Tweet { username: String, content: String, } // Implementation for Article impl Summary for Article { fn summarize(&self) -> String { format!("{} by {}", self.title, self.author) } } // Implementation for Tweet impl Summary for Tweet { fn summarize(&self) -> String { format!("@{}: {}", self.username, self.content) } } // Function accepting any type implementing Summary fn notify(item: &impl Summary) { println!("Breaking news: {}", item.summarize()); } // Equivalent syntax with trait bound fn notify_generic(item: &T) { println!("Breaking news: {}", item.summarize()); } fn main() { let article = Article { title: String::from("Rust 2026"), author: String::from("Community"), content: String::from("..."), }; let tweet = Tweet { username: String::from("rustlang"), content: String::from("Rust is awesome!"), }; notify(&article); notify(&tweet); } ``` ## 標準ライブラリの主要コレクション Rustの標準ライブラリには強力なコレクション型が用意されています。 ```rust // collections.rs use std::collections::HashMap; fn main() { // Vec: dynamic array let mut numbers: Vec = Vec::new(); numbers.push(1); numbers.push(2); numbers.push(3); // vec! macro for initialization let nums = vec![1, 2, 3, 4, 5]; // Iteration for n in &nums { println!("{}", n); } // Functional methods let doubled: Vec = nums.iter().map(|x| x * 2).collect(); let sum: i32 = nums.iter().sum(); let evens: Vec<&i32> = nums.iter().filter(|x| *x % 2 == 0).collect(); // String: growable UTF-8 string let mut s = String::from("Hello"); s.push_str(", World!"); s.push('!'); // Concatenation let s1 = String::from("Hello, "); let s2 = String::from("World!"); let s3 = s1 + &s2; // s1 moved, s2 borrowed // or with format! let s4 = format!("{}{}", "Hello, ", "World!"); // HashMap let mut scores: HashMap = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Red"), 50); // Access with get (returns Option) if let Some(score) = scores.get("Blue") { println!("Blue: {}", score); } // Entry API for conditional insertion scores.entry(String::from("Yellow")).or_insert(25); } ``` ## Rustにおけるイディオマティックなエラーハンドリング 適切なエラーハンドリングはRust開発において不可欠です。ここでは推奨されるパターンを紹介します。 ```rust // error_handling.rs use std::fs::File; use std::io::{self, Read}; use std::num::ParseIntError; // Define a custom error type #[derive(Debug)] enum AppError { Io(io::Error), Parse(ParseIntError), Custom(String), } // Implement From for automatic conversion impl From for AppError { fn from(err: io::Error) -> Self { AppError::Io(err) } } impl From for AppError { fn from(err: ParseIntError) -> Self { AppError::Parse(err) } } // Function returning Result with custom error fn read_number_from_file(path: &str) -> Result { let mut file = File::open(path)?; // io::Error -> AppError let mut content = String::new(); file.read_to_string(&mut content)?; let number: i32 = content.trim().parse()?; // ParseIntError -> AppError Ok(number) } fn main() { match read_number_from_file("number.txt") { Ok(n) => println!("Number: {}", n), Err(AppError::Io(e)) => println!("IO error: {}", e), Err(AppError::Parse(e)) => println!("Parse error: {}", e), Err(AppError::Custom(msg)) => println!("Error: {}", msg), } } ``` > **おすすめのクレート** > > 実際のプロジェクトでは、`thiserror`クレート(ライブラリ向け)と`anyhow`クレート(アプリケーション向け)を活用することで、エラーハンドリングの実装を大幅に簡素化できます。 ## Rustのテスト機能 Rustはテストフレームワークを言語自体に統合しています。外部ライブラリなしで、すぐにテストを書き始めることが可能です。 ```rust // lib.rs pub fn add(a: i32, b: i32) -> i32 { a + b } pub fn divide(a: i32, b: i32) -> Result { if b == 0 { Err(String::from("Division by zero")) } else { Ok(a / b) } } // Test module (compiled only for `cargo test`) #[cfg(test)] mod tests { use super::*; #[test] fn test_add() { assert_eq!(add(2, 3), 5); } #[test] fn test_add_negative() { assert_eq!(add(-1, 1), 0); } #[test] fn test_divide_success() { assert_eq!(divide(10, 2), Ok(5)); } #[test] fn test_divide_by_zero() { assert!(divide(10, 0).is_err()); } #[test] #[should_panic(expected = "index out of bounds")] fn test_panic() { let v = vec![1, 2, 3]; let _ = v[99]; // Panic! } } ``` ## まとめ Rustはメモリ安全性とパフォーマンスを両立する独自のパラダイムを提供します。所有権と借用の概念は最初こそ制約に感じますが、実践を重ねることで自然に身につきます。Rustコンパイラは強力な味方であり、そのエラーメッセージは業界で最も優れたものの一つです。 ### Rust学習チェックリスト - rustupでRustをインストールし、Cargoの基本コマンドを習得する - 不変性とmutによる明示的な可変性の違いを理解する - 所有権の3つのルールを確実にマスターする - `&`と`&mut`を使った借用を実践で身につける - nullや例外の代わりに`Option`と`Result`を活用する - `#[test]`アトリビュートでテストを記述する Rustコミュニティは協力的で、学習リソースも豊富です。公式ドキュメント「The Rust Programming Language」は無料でオンライン公開されています。ここで紹介した基礎を固めた上で、async/await、マクロ、WebAssemblyなどの高度なトピックへ進むことが推奨されます。 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/rust/rust-basics-experienced-developers