Rust
エンジニアのためのWebチートシート
Rustは、安全性、速度、並行性を重視したシステムプログラミング言語です。 所有権システムによりメモリ安全性をコンパイル時に保証します。 基本構文、所有権、データ型、トレイト、エラー処理、コレクションなどをチートシートにまとめました。
基本構文
変数と定数
let, let mut, const によるバインディングと型推論、シャドーイングです。
let x = 5; // 不変(デフォルト) let name: &str = "Rust"; // 型注釈付き let mut count = 0; // 可変バインディング count += 1; const MAX_SIZE: u32 = 100; // 定数(型注釈必須) const PI: f64 = 3.141592653589793;// 型推論 let x = 42; // i32 let y = 3.14; // f64 let flag = true; // bool // シャドーイング(同名で再束縛、型変更も可能) let x = 5; let x = x + 1; // 6 let x = "hello"; // 型も変更可能
Rustの基本データ型の一覧です。
| 型 | 説明 |
|---|---|
i8, i16, i32, i64, i128 | 符号付き整数 |
u8, u16, u32, u64, u128 | 符号なし整数 |
isize, usize | ポインタサイズ整数(64bit環境では64bit) |
f32, f64 | 浮動小数点数 |
bool | true / false |
char | Unicodeスカラー値(4バイト) |
&str | 文字列スライス(不変参照) |
String | ヒープ割り当て文字列(可変、所有) |
() | ユニット型(値なし) |
出力とフォーマット
println!, format! マクロによる出力とフォーマット指定です。
println!("Hello, World!"); // 改行付き print!("Hello "); // 改行なし eprintln!("Error!"); // 標準エラー出力 println!("Name: {}", name); println!("{} + {} = {}", 1, 2, 3); println!("{name} is {age}", name="Rust", age=9);// デバッグ出力 println!("{:?}", vec![1, 2, 3]); // [1, 2, 3] println!("{:#?}", my_struct); // 整形出力 // 数値フォーマット println!("{:.2}", 3.14159); // 3.14 println!("{:08b}", 42); // 00101010(2進数) println!("{:x}", 255); // ff(16進数) println!("{:>10}", "right"); // 右寄せ let s = format!("Hello, {}!", name); // 文字列生成
所有権と参照
所有権ルール
所有権の3つのルール、ムーブセマンティクス、スコープです。
// 1. 各値は1つの所有者を持つ // 2. 所有者は一度に1つだけ // 3. 所有者がスコープを抜けると値は破棄される let s1 = String::from("hello"); let s2 = s1; // s1 → s2 にムーブ // println!("{}", s1); // エラー!s1は無効// 関数への受け渡しでもムーブが発生 fn take_ownership(s: String) { println!("{}", s); } // s はここで drop let s = String::from("hello"); take_ownership(s); // println!("{}", s); // エラー!// 所有権を返す fn give_back(s: String) -> String { s } // スコープと Drop { let s = String::from("hello"); } // s はここで自動的に drop
借用と参照
&参照、&mut参照、借用ルールです。
// 不変参照(&T): 複数可能 let s = String::from("hello"); let r1 = &s; let r2 = &s; println!("{}, {}", r1, r2); // 可変参照(&mut T): 1つだけ let mut s = String::from("hello"); let r = &mut s; r.push_str(", world");// 借用ルール // 1. 不変参照は同時に複数OK // 2. 可変参照は同時に1つだけ // 3. 不変・可変参照は同時に存在不可 let mut s = String::from("hello"); let r1 = &s; let r2 = &s; // let r3 = &mut s; // エラー! println!("{}, {}", r1, r2); let r3 = &mut s; // OK(r1, r2 のスコープ外) fn calc_length(s: &String) -> usize { s.len() }
Copy と Clone
Copy trait、Clone trait、値型と参照型の違いです。
// Copy trait: スタック上のデータをビットコピー let x: i32 = 42; let y = x; // コピー(x はまだ有効) // Copy を実装: 整数型, f32/f64, bool, char // Clone trait: 明示的なディープコピー let s1 = String::from("hello"); let s2 = s1.clone(); // ヒープデータもコピー println!("{}, {}", s1, s2);#[derive(Copy, Clone)] struct Point { x: f64, y: f64 } // Clone のみ(ヒープデータを含む場合) #[derive(Clone)] struct User { name: String, // String は Copy でない age: u32, }
データ型
文字列
String と &str の違い、変換、主要メソッドです。
let s: &str = "hello"; // 文字列スライス(不変) let mut s = String::from("hello"); // ヒープ割り当て(可変) s.push_str(", world"); s.push('!'); // 変換 let s1: String = "hello".to_string(); let s2: &str = &s1; // String → &str// 主要メソッド s.len(); s.is_empty(); s.contains("world"); s.starts_with("hello"); s.replace("world", "Rust"); s.trim(); s.to_uppercase(); s.split(',').collect::<Vec<&str>>(); // 文字列結合 let s = format!("{} {}", "hello", "world"); let s = ["hello", " ", "world"].concat();
配列・タプル・スライス
固定長配列、タプル、スライスです。
// 配列(固定長、同一型) let arr: [i32; 5] = [1, 2, 3, 4, 5]; let zeros = [0; 10]; // 10要素すべて0 let first = arr[0]; let slice: &[i32] = &arr[1..3]; // [2, 3]// タプル(異なる型を格納可能) let tup: (i32, f64, &str) = (42, 3.14, "hello"); let (x, y, z) = tup; // 分配束縛 let first = tup.0; // インデックスアクセス let unit: () = (); // ユニットタプル
型変換
as キャスト、From/Into、TryFrom/TryInto です。
// as キャスト let x: i32 = 42; let y: f64 = x as f64; let w: i8 = 255u8 as i8; // -1(オーバーフロー注意) // From / Into トレイト let s: String = String::from("hello"); let n: i64 = i64::from(42i32); let n: i64 = 42i32.into();// TryFrom(失敗する可能性のある変換) use std::convert::TryFrom; let n: Result<u8, _> = u8::try_from(256i32); // Err // 文字列 ↔ 数値 let n: i32 = "42".parse().unwrap(); let n = "42".parse::<i32>().unwrap(); // ターボフィッシュ let s: String = 42.to_string();
制御フロー
if / else
式としての if、if let です。
if x > 0 { println!("positive"); } else if x == 0 { println!("zero"); } else { println!("negative"); } // 式としての if(値を返す) let result = if x > 0 { "positive" } else { "negative" };// if let(パターンマッチの糖衣構文) let opt: Option<i32> = Some(42); if let Some(value) = opt { println!("Got: {}", value); } // let-else(Rust 1.65+) let Some(value) = opt else { return; };
match & パターンマッチ
match式、パターン、ガード、分配束縛です。
// 基本(全パターン網羅が必要) match value { 1 => println!("one"), 2 | 3 => println!("two or three"), 4..=9 => println!("four to nine"), _ => println!("other"), } // 式として使う let msg = match status { 200 => "OK", 404 => "Not Found", _ => "Unknown", };// 分配束縛 match (3, 5) { (0, 0) => println!("origin"), (x, 0) => println!("x-axis: {}", x), (x, y) => println!("({}, {})", x, y), } // ガード条件 match num { n if n < 0 => println!("negative"), n => println!("{}", n), }
ループ
loop, while, for, break値返却, continue, ラベルです。
// loop(無限ループ、値を返せる) let result = loop { if condition { break 42; } }; // while let mut n = 0; while n < 10 { n += 1; } // while let let mut stack = vec![1, 2, 3]; while let Some(top) = stack.pop() { println!("{}", top); }// for(範囲) for i in 0..5 { } // 0, 1, 2, 3, 4 for i in 0..=5 { } // 0, 1, 2, 3, 4, 5 // for(イテレータ) for n in &vec![10, 20, 30] { println!("{}", n); } // ラベル付きループ 'outer: for i in 0..5 { for j in 0..5 { if i + j > 4 { break 'outer; } } }
関数とクロージャ
関数定義
パラメータ、戻り値、式ベースの戻り値です。
fn greet(name: &str) -> String { format!("Hello, {}!", name) } // セミコロンなし = 暗黙の return fn add(a: i32, b: i32) -> i32 { a + b } // 複数の戻り値(タプル) fn swap(a: i32, b: i32) -> (i32, i32) { (b, a) } let (x, y) = swap(1, 2);// 参照を受け取る fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &b) in bytes.iter().enumerate() { if b == b' ' { return &s[..i]; } } s } // 関数ポインタ fn apply(f: fn(i32) -> i32, x: i32) -> i32 { f(x) } let result = apply(|x| x * 2, 5); // 10
クロージャ
|x| 構文、キャプチャ方式(Fn/FnMut/FnOnce)です。
let add = |a, b| a + b; let result = add(1, 2); // 3 let add = |a: i32, b: i32| -> i32 { a + b }; // 型注釈付き // 環境のキャプチャ let x = 10; let add_x = |n| n + x; // x を借用 println!("{}", add_x(5)); // 15// キャプチャ方式: Fn(&self), FnMut(&mut self), FnOnce(self) // move クロージャ(所有権をムーブ) let name = String::from("Rust"); let greet = move || println!("Hello, {}!", name); greet(); // println!("{}", name); // エラー! fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x) }
イテレータ
iter(), map, filter, collect, fold, enumerate です。
let nums = vec![1, 2, 3, 4, 5]; // iter(): &T, into_iter(): T, iter_mut(): &mut T let doubled: Vec<i32> = nums.iter() .map(|&x| x * 2).collect(); // [2, 4, 6, 8, 10] let evens: Vec<&i32> = nums.iter() .filter(|&&x| x % 2 == 0).collect(); // [2, 4] let sum = nums.iter().fold(0, |acc, &x| acc + x);// チェーン let result: Vec<i32> = (1..=10) .filter(|x| x % 2 == 0) .map(|x| x * x) .collect(); // [4, 16, 36, 64, 100] // その他 nums.iter().any(|&x| x > 3); // true nums.iter().find(|&&x| x > 3); // Some(&4) nums.iter().sum::<i32>(); // 15 nums.iter().min(); // Some(&1) nums.iter().count(); // 5
構造体・列挙型・トレイト
構造体 & メソッド
struct 定義、impl、&self/&mut self、関連関数です。
struct User { name: String, age: u32, active: bool, } let user = User { name: String::from("Alice"), age: 30, active: true, }; let name = String::from("Bob"); let user2 = User { name, age: 25, active: true }; // 省略記法 let user3 = User { age: 35, ..user2 }; // 更新構文impl User { fn new(name: &str, age: u32) -> Self { Self { name: name.to_string(), age, active: true } } fn greet(&self) -> String { format!("Hi, I'm {} ({})", self.name, self.age) } fn set_age(&mut self, age: u32) { self.age = age; } } let mut u = User::new("Alice", 30); u.set_age(31);
列挙型
enum 定義、データ付きバリアント、Option/Result です。
enum Direction { Up, Down, Left, Right } let dir = Direction::Up; // データ付きバリアント enum Message { Quit, Echo(String), Move { x: i32, y: i32 }, Color(u8, u8, u8), }match msg { Message::Quit => println!("quit"), Message::Echo(text) => println!("{}", text), Message::Move { x, y } => println!("{},{}", x, y), Message::Color(r, g, b) => println!("#{:02x}{:02x}{:02x}", r, g, b), } // Option / Result let some_val: Option<i32> = Some(42); let ok_val: Result<i32, String> = Ok(42);
トレイト
trait 定義、impl Trait、デフォルト実装、トレイト境界です。
trait Summary { fn summarize(&self) -> String; fn preview(&self) -> String { // デフォルト実装 format!("{}...", &self.summarize()[..20]) } } struct Article { title: String, content: String } impl Summary for Article { fn summarize(&self) -> String { format!("{}: {}", self.title, self.content) } }// トレイト境界 fn notify(item: &impl Summary) { println!("{}", item.summarize()); } // where 句 fn process<T>(item: &T) where T: Summary + Clone { println!("{}", item.summarize()); } // derive マクロ #[derive(Debug, Clone, PartialEq)] struct Point { x: f64, y: f64 }
エラーハンドリング
Result & Option
Ok/Err、Some/None、unwrap、expect です。
fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { Err("division by zero".into()) } else { Ok(a / b) } } match divide(10.0, 3.0) { Ok(result) => println!("{:.2}", result), Err(e) => println!("Error: {}", e), }fn find_user(id: u32) -> Option<String> { if id == 1 { Some("Alice".to_string()) } else { None } } // unwrap / expect(None/Err で panic) let val = Some(42).unwrap(); let val = Some(42).expect("msg"); // デフォルト値 let val = None.unwrap_or(0); let val = None.unwrap_or_else(|| compute_default());
? 演算子 & チェーン
?演算子、map、and_then、unwrap_or です。
// ? 演算子(Err/None を早期リターン) fn read_file(path: &str) -> Result<String, std::io::Error> { let content = std::fs::read_to_string(path)?; Ok(content.to_uppercase()) } fn first_line(path: &str) -> Result<String, std::io::Error> { let content = std::fs::read_to_string(path)?; let line = content.lines().next() .ok_or(std::io::Error::new( std::io::ErrorKind::InvalidData, "empty file" ))?; Ok(line.to_string()) }// Option のメソッドチェーン let val: Option<i32> = Some(5); val.map(|x| x * 2); // Some(10) val.and_then(|x| Some(x + 1)); // Some(6) val.unwrap_or(0); // 5 val.is_some(); // true val.is_none(); // false
カスタムエラー
Error trait 実装、thiserror/anyhow の紹介です。
#[derive(Debug)] enum AppError { NotFound(String), Io(std::io::Error), } impl std::fmt::Display for AppError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { AppError::NotFound(msg) => write!(f, "Not found: {}", msg), AppError::Io(e) => write!(f, "IO error: {}", e), } } } impl std::error::Error for AppError {}// From で自動変換(? 演算子で使用可能に) impl From<std::io::Error> for AppError { fn from(e: std::io::Error) -> Self { AppError::Io(e) } } // thiserror(ボイラープレート削減) // #[derive(thiserror::Error, Debug)] // enum AppError { // #[error("Not found: {0}")] // NotFound(String), // }
コレクション
Vec
生成、push、pop、インデックス、スライス、イテレーションです。
let mut v: Vec<i32> = Vec::new(); let v2 = vec![1, 2, 3, 4, 5]; let v3 = vec![0; 10]; // 10要素すべて0 v.push(1); v.push(2); let last = v.pop(); // Some(2) let first = v[0]; // パニックの可能性あり let first = v.get(0); // Option<&i32>(安全) let slice = &v[1..3];for val in &v { println!("{}", val); } for val in &mut v { *val *= 2; } v.len(); v.is_empty(); v.contains(&2); v.sort(); v.dedup(); // 連続する重複を除去 v.retain(|&x| x > 2); // 条件で絞り込み v.extend([4, 5, 6]);
HashMap
insert、get、entry API、イテレーションです。
use std::collections::HashMap; let mut map = HashMap::new(); map.insert("Alice", 30); map.insert("Bob", 25); let age = map.get("Alice"); // Option<&i32> map.contains_key("Alice"); // true map.entry("Charlie").or_insert(35); // キーが無い場合のみ挿入// ワードカウント例 let mut counts = HashMap::new(); for word in "hello world hello".split_whitespace() { *counts.entry(word).or_insert(0) += 1; } for (key, val) in &map { println!("{}: {}", key, val); } map.remove("Bob");
イテレータパターン
メソッドチェーン、collect、変換パターンです。
let words = vec!["hello", "world", "rust"]; let result: String = words.iter() .map(|w| w.to_uppercase()) .collect::<Vec<_>>() .join(", "); // "HELLO, WORLD, RUST" // flatten let nested = vec![vec![1, 2], vec![3, 4]]; let flat: Vec<i32> = nested.into_iter() .flatten().collect(); // [1, 2, 3, 4]// zip let pairs: Vec<_> = ["Alice", "Bob"].iter() .zip([30, 25].iter()).collect(); // partition let (evens, odds): (Vec<i32>, Vec<i32>) = vec![1, 2, 3, 4, 5].into_iter() .partition(|&x| x % 2 == 0); // chunks / windows for chunk in [1,2,3,4,5].chunks(2) { } // [1,2],[3,4],[5] for w in [1,2,3,4,5].windows(3) { } // [1,2,3],[2,3,4],...
モジュール & Cargo
モジュールシステム
mod, use, pub, super, crate です。
mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } fn private_fn() {} // 非公開 pub mod advanced { pub fn sqrt(x: f64) -> f64 { x.sqrt() } } } use math::add; use std::collections::{HashMap, HashSet}; use std::io::Result as IoResult; pub use math::add; // 再エクスポート// ファイル構成 // src/main.rs, src/lib.rs // src/math/mod.rs, src/math/advanced.rs // super, crate, self mod parent { pub fn hello() {} pub mod child { pub fn call_parent() { super::hello(); // 親モジュール crate::some_fn(); // クレートルート } } }
Cargo コマンド
よく使うCargoのCLIコマンドです。
# プロジェクト作成 cargo new myproject # バイナリ cargo new mylib --lib # ライブラリ # ビルド & 実行 cargo build # デバッグビルド cargo build --release # リリースビルド cargo run # ビルド & 実行# テスト cargo test # 全テスト実行 cargo test test_name # 特定のテスト # 依存関係 & コード品質 cargo add serde # クレート追加 cargo add tokio --features full cargo fmt # フォーマット cargo clippy # リンター cargo check # コンパイルチェック cargo doc --open # ドキュメント生成