ホームに戻る
Rustコース
メモリ安全性と並行性を重視したシステムプログラミング言語を学びましょう
初
初級
無料で学習可能
初級基本構文
問題1: Hello World
Rustプログラミングの第一歩として、画面に文字を出力する方法を学びます。println!マクロは標準出力にテキストを表示する最も基本的な方法です。マクロは関数とは異なり、名前の最後に感嘆符(!)が付きます。これはRustの強力な機能の一つで、コンパイル時にコードを生成します。
初級基本構文
問題2: 変数の宣言
Rustでは変数を宣言するためにletキーワードを使用します。他の多くの言語と異なり、Rustの変数はデフォルトで不変(イミュータブル)です。これは安全性を重視するRustの設計哲学の表れで、変数の値が予期せず変更されることを防ぎます。一度値を代入した変数は、その後変更することができません。
初級基本構文
問題3: 可変変数
Rustでは変数の値を変更したい場合、明示的にmutキーワードを使って可変性を宣言する必要があります。これにより、どの変数が変更される可能性があるのかがコード上で明確になり、バグの発見や防止に役立ちます。mutはmutable(可変)の略で、letの後に配置します。
初級基本構文
問題4: 基本的なデータ型
Rustには様々な基本データ型があります。整数型(i32など)、浮動小数点型(f64など)、論理型(bool)、文字型(char)が代表的です。Rustは強い型推論を持つため、多くの場合型を明示的に書く必要はありませんが、必要に応じて型注釈を付けることもできます。
初級基本構文
問題5: 算術演算子
Rustの算術演算子は他の多くの言語と似ていますが、重要な違いがあります。整数同士の除算は整数除算となり、小数点以下は切り捨てられます。浮動小数点数の除算を行いたい場合は、少なくとも一方を浮動小数点型にする必要があります。また、Rustは型の安全性を重視するため、異なる型同士の演算はコンパイルエラーになります。
初級基本構文
問題6: 文字列型の基礎
Rustには2つの主要な文字列型があります。&strは文字列スライスと呼ばれ、文字列データへの借用された参照です。文字列リテラルは常に&str型です。一方、Stringは所有権を持つ、可変長の文字列型です。Stringは動的に成長でき、文字列の連結や変更が可能です。この所有権の概念はRustの核心的な特徴の一つです。
初級基本構文
問題7: 比較演算子と論理演算子
Rustの比較演算子は数値や文字列などの値を比較し、bool型(true/false)を返します。論理演算子は複数の条件を組み合わせる際に使用します。&&(AND)は両方の条件が真の場合に真、||(OR)はどちらか一方が真なら真、!(NOT)は真偽値を反転させます。これらの演算子は条件分岐やループ制御で頻繁に使用されます。
初級基本構文
問題8: 型変換
Rustでは異なる型の間で演算を行うことはできません。型を変換するにはasキーワードを使用します。整数から浮動小数点数、浮動小数点数から整数、文字から数値など、様々な変換が可能です。ただし、精度が失われる可能性がある変換(浮動小数点数から整数など)には注意が必要です。
初級基本構文
問題9: 定数と静的変数
Rustには2種類のグローバル変数があります。constは定数で、コンパイル時に値が決まり変更できません。staticは静的変数で、プログラム全体で共有される唯一のインスタンスです。変数名は慣習的にSCREAMING_SNAKE_CASEを使います。静的変数の変更にはunsafeが必要です。
初級基本構文
問題10: コメントとドキュメント
Rustには3種類のコメントがあります。//は単一行コメント、/* */は複数行コメント、///はドキュメントコメントです。ドキュメントコメントは関数や構造体の説明に使用され、cargo docコマンドでHTMLドキュメントを生成できます。適切なコメントはコードの可読性を大幅に向上させます。
初級基本構文
問題11: シャドーイング
Rustでは同じ名前の変数を再宣言できます。これをシャドーイングと呼びます。新しい変数は前の変数を覆い隠し、異なる型の値も持てます。これはmutとは異なり、letキーワードを使って新しい変数を作成します。シャドーイングは値の変換や、同じ名前で異なる意味を持つ変数を扱う際に便利です。
初級基本構文
問題12: 複合型の基礎
Rustの主な複合型にはタプルと配列があります。タプルは異なる型の値を格納でき、括弧()で定義します。配列は同じ型の値のみを格納し、角括弧[]で定義します。タプルは要素数が固定で、パターンマッチングで分解できます。配列はインデックスでアクセスし、0から始まります。
初級制御構造
問題13: if式の基礎
Rustのifは文ではなく式です。つまり値を返すことができます。条件分岐の基本的な使い方に加えて、変数に条件の結果を代入できます。条件部分に括弧は不要で、各分岐の最後の式が返される値になります。すべての分岐は同じ型の値を返す必要があります。
初級制御構造
問題14: if-else式
Rustではif-else ifを使って複数の条件を順番にチェックできます。最初に真となった条件の分岐が実行されます。if式として使用する場合、すべての分岐が同じ型の値を返す必要があります。else節は省略可能ですが、式として使う場合は必須です。複雑な条件分岐では、後で学ぶmatch式の方が適している場合もあります。
初級制御構造
問題15: match式の基礎
match式はRustの強力なパターンマッチング機能です。値を複数のパターンと照合し、最初にマッチしたパターンのコードを実行します。すべての可能性をカバーする必要があり(網羅性)、これによりバグを防げます。アンダースコア(_)はワイルドカードパターンで、他のすべてのケースにマッチします。
初級制御構造
問題16: loop文
loopは無限ループを作成します。breakで明示的に脱出するまで実行を続けます。whileやforと異なり、loopは値を返すことができます。breakに値を渡すと、その値がloop式の結果になります。これは計算結果を返すループや、リトライ処理などで便利です。continueで次の反復にスキップすることもできます。
初級制御構造
問題17: while文
while文は条件が真の間、処理を繰り返します。条件が偽になるとループを終了します。カウンタ変数と組み合わせて、特定の回数だけ処理を繰り返すのによく使われます。loopとは異なり、whileは値を返すことができません。無限ループを避けるため、ループ内で条件を変更する処理を含める必要があります。
初級制御構造
問題18: for文とイテレータ
forループはイテレータを使って要素を順番に処理します。範囲(Range)は最もよく使われるイテレータで、1..5は1から4まで、1..=5は1から5までを表します。配列やベクタなども直接イテレートできます。forループは所有権の扱いが安全で、Rustで最も推奨されるループ構造です。
初級制御構造
問題19: break値の返却
breakは単にループを終了するだけでなく、値を返すこともできます。これはloop式でのみ可能で、whileやforでは使えません。ラベル付きループを使うと、ネストしたループから特定のループを抜けることができます。ラベルはシングルクォートで始まり、コロンで終わります(例:'outer:)。
初級制御構造
問題20: continue文
continue文は現在のループイテレーションをスキップし、次のイテレーションに進みます。breakとは異なり、ループを終了せずに特定の条件で処理をスキップしたい場合に使用します。フィルタリングやエラー処理でよく使われ、ネストを減らしてコードを読みやすくします。continueもラベルと組み合わせて使用できます。
初級関数
問題21: 関数の定義
Rustの関数はfnキーワードで定義します。引数には型注釈が必須で、戻り値がある場合は->の後に型を指定します。関数名はスネークケース(snake_case)で記述するのが慣例です。引数の型と戻り値の型を明示することで、コンパイラが型安全性を保証し、関数の使い方が明確になります。
初級関数
問題22: 文と式
Rustでは文と式の区別が重要です。文はセミコロンで終わり、値を返しません。式は値を評価し、セミコロンを付けません。関数の最後の式は自動的に戻り値になります。return文を使えば早期リターンも可能です。この仕組みにより、Rustでは多くのものが式として扱われ、柔軟なコードが書けます。
初級関数
問題23: 複数の引数
Rustの関数は複数の引数を受け取ることができます。各引数には必ず型注釈が必要で、引数はカンマで区切ります。引数の順序は重要で、関数呼び出し時に同じ順序で値を渡す必要があります。型注釈を必須とすることで、関数のインターフェースが明確になり、型の不一致によるエラーを防げます。
初級関数
問題24: Unit型
Unit型()は「値なし」を表す特別な型です。値を返さない関数は暗黙的にUnit型を返します。println!のような副作用のみの関数で使われます。Unit型は空のタプルとも呼ばれ、唯一の値()を持ちます。明示的に-> ()と書くこともできますが、通常は省略します。
初級関数
問題25: 早期リターン
return文を使うと関数から早期に脱出できます。エラー処理や条件チェックで頻繁に使われ、ガード節と呼ばれるパターンを実装できます。早期リターンにより、ネストを減らし、正常系の処理を関数の最後に置くことができます。これにより、コードの可読性が向上し、エラーケースが明確になります。
初級関数
問題26: 関数内関数
Rustでは関数内に別の関数を定義できます。内部関数はそのスコープ内でのみ有効で、外部からアクセスできません。これによりヘルパー関数を隠蔽でき、コードの整理に役立ちます。内部関数は外部変数をキャプチャしないため、クロージャとは異なります。各関数は独立しており、引数を通じてのみデータを受け渡します。
初級関数
問題27: 高階関数の基礎
高階関数は関数を引数として受け取る関数です。Rustではfn型を使って関数ポインタを表現します。関数を値として扱えるため、動的に処理を切り替えたり、共通の処理パターンを抽象化できます。これは関数型プログラミングの基本的な概念で、コードの再利用性と柔軟性を高めます。
初級関数
問題28: 再帰関数
再帰関数は自分自身を呼び出す関数です。複雑な問題を小さな部分問題に分解して解く際に有効です。基底条件(終了条件)を必ず設定し、無限再帰を避ける必要があります。Rustではスタックサイズに制限があるため、深い再帰はスタックオーバーフローを引き起こす可能性があります。
初級所有権
問題29: 所有権の移動
Rustの所有権システムは、メモリ安全性を保証する中核機能です。値の所有者は常に一つだけで、代入や関数呼び出しで所有権が移動(move)します。移動後、元の変数は使用できません。これによりダブルフリーや無効な参照を防ぎます。String型のようなヒープ上のデータで特に重要です。
初級所有権
問題30: 借用(参照)
借用は&記号で作成する不変参照です。所有権を移動せずに値へのアクセスを提供します。複数の不変参照を同時に作成でき、元の変数も使用可能です。関数に参照を渡すと、関数実行後も元の変数を使い続けられます。これにより効率的で安全なデータ共有が可能になります。
初級所有権
問題31: 可変参照
可変参照(&mut)は値を変更できる参照です。重要な制約として、一度に一つの可変参照しか存在できません。これによりデータ競合を防ぎます。可変参照を作成するには、元の変数もmutである必要があります。関数に可変参照を渡すと、関数内で値を変更できます。
初級所有権
問題32: 参照のルール
Rustの参照には厳格なルールがあります。不変参照は複数持てますが、可変参照は一つだけです。さらに、不変参照と可変参照は同時に存在できません。これらのルールによりデータ競合を防ぎます。また、参照のライフタイムにより、ダングリング参照(無効なメモリを指す参照)も防がれます。
初級所有権
問題33: Copy型とClone
基本的な型(整数、浮動小数点数、bool、char)はCopyトレイトを実装しており、代入時に自動的にコピーされます。一方、String、Vec等のヒープを使う型は移動します。これらの型を複製するにはclone()メソッドを使います。cloneは明示的な深いコピーを行い、元の値も使い続けられます。
初級所有権
問題34: 文字列スライス
&str型は文字列スライスと呼ばれ、文字列の一部(または全体)への参照です。String型から&strを作成でき、範囲指定で部分文字列を参照できます。文字列リテラルも&str型です。スライスは所有権を持たず、元の文字列を借用します。関数の引数や戻り値でよく使われます。
初級所有権
問題35: 配列とスライス
配列は固定長で同じ型の要素を持つデータ構造です。[T; N]と表記し、Tは型、Nは要素数です。スライス&[T]は配列の一部(または全体)への参照で、長さが動的です。配列は所有権を持ちますが、スライスは借用です。関数の引数にはスライスを使うことで、配列やベクタなど様々なコレクションを受け取れます。
初級所有権
問題36: タプル
タプルは異なる型の値をまとめて保持できる複合型です。要素数と各要素の型は固定で、括弧()で定義します。要素へのアクセスは0から始まるインデックス(.0、.1など)を使います。パターンマッチングで個別の変数に分解でき、関数から複数の値を返す際によく使われます。
初級構造体
問題37: 構造体の基礎
構造体(struct)は関連するデータをまとめて名前を付けた型です。各データはフィールドと呼ばれ、名前と型を持ちます。構造体のインスタンスを作成し、ドット記法でフィールドにアクセスします。構造体全体をmutにすると、すべてのフィールドが可変になります。カスタム型を作る基本的な方法です。
初級所有権
問題38: スライスの操作
スライスは配列や文字列の一部分への参照です。範囲指定(..)でスライスを作成でき、split_atメソッドで指定位置で分割できます。スライスは元のデータを所有せず借用するため、効率的にデータの部分アクセスが可能です。配列、ベクタ、文字列など様々なコレクションで使用でき、Rustの重要な機能の一つです。
初級所有権
問題39: 所有権とループ
forループでコレクションを扱う際、所有権の扱い方により3つのパターンがあります。&でイテレートすると借用、&mutで可変借用、何もつけないと所有権が移動します。借用なら元のデータは使用可能ですが、所有権が移動すると元の変数は使えなくなります。この仕組みにより、安全で効率的なループ処理が実現されます。
初級所有権
問題40: 関数と所有権
関数の引数や戻り値で所有権がどう扱われるかを理解することは重要です。値渡しでは所有権が移動し、参照渡しでは借用されます。関数から値を返すと、その所有権は呼び出し元に移ります。この仕組みにより、メモリ安全性を保ちながら柔軟なデータの受け渡しが可能になります。適切な選択により効率的なプログラムが書けます。
中
中級
無料で学習可能
中級データ構造
問題41: ベクタの基礎
Vec'<'T'>'はRustの動的配列で、実行時にサイズを変更できます。vec!マクロで初期化でき、Vec::newで空のベクタを作成します。要素は同じ型でなければならず、ヒープに格納されます。配列と違い、実行時に要素を追加・削除できるため、多くの場面で使用されます。ベクタは自動的にメモリを管理し、容量が不足すると自動的に拡張されます。Rustのコレクション型の中で最も基本的で重要な型です。
中級データ構造
問題42: ベクタのメソッド
ベクタには多数の便利なメソッドがあります。pushで末尾に追加、popで末尾から取り出し、lenで長さを取得します。popはOption型を返し、空の場合はNoneになります。iter()でイテレータに変換でき、collect()でイテレータからベクタを作成できます。これらのメソッドを組み合わせることで、効率的なデータ操作が可能です。メモリ効率も考慮された設計になっています。
中級データ構造
問題43: 文字列の操作
RustのString型は可変で成長可能なUTF-8文字列です。String::fromやto_stringで作成し、push_strで文字列を結合できます。format!マクロは複数の値を組み合わせて新しい文字列を作成します。&strとStringの相互変換も重要です。文字列操作はWebアプリケーションやCLIツールなど、多くのプログラムで必要となる基本的な操作です。
中級データ構造
問題44: HashMap基礎
HashMap'<'K, V'>'はキーと値のペアを保存するデータ構造です。PythonのdictやJavaScriptのObjectに似ています。insertでキーと値を追加、getで値を取得、removeで削除します。getはOption型を返すため、キーが存在しない場合も安全に扱えます。ハッシュテーブルのため高速な検索が可能で、多くの用途で使用されます。
中級データ構造
問題45: HashMapの応用
HashMapのentry APIはキーの存在確認と更新を効率的に行えます。or_insertはキーがない場合にデフォルト値を挿入し、and_modifyは既存値を変更します。これにより、単語カウントやスコア集計などの処理が簡潔に書けます。パフォーマンスも優れており、実用的なパターンです。
中級エラー処理
問題46: Option型
Option'<'T'>'はRustのnull安全性を実現する型で、値があるかないかを表現します。Some(T)は値がある場合、Noneは値がない場合を表します。matchでパターンマッチングしたり、unwrapやunwrap_orなどのメソッドで値を取り出せます。nullポインタエラーをコンパイル時に防ぐ重要な機能です。
中級エラー処理
問題47: Result型
Result'<'T, E'>'は成功またはエラーを表現する型で、Rustのエラーハンドリングの中核です。Ok(T)は成功した値、Err(E)はエラー情報を保持します。ファイル操作やネットワーク通信など、失敗する可能性がある操作で使用されます。matchやif letで処理し、?演算子で早期リターンも可能です。
中級データ構造
問題48: 列挙型(enum)
enumは複数のバリアントから一つを選ぶ型で、各バリアントは異なるデータを持てます。シンプルな状態を表現したり、異なる種類のデータを一つの型で扱えます。match文で全バリアントを網羅的に処理する必要があり、これにより安全性が保証されます。Rustの型システムの中でも特に強力な機能です。
中級構造体
問題49: 構造体メソッド
構造体にメソッドを追加するにはimplブロックを使います。&selfは借用、&mut selfは可変借用、selfは所有権を受け取ります。関連関数(コンストラクタ)はselfパラメータを持たず、::で呼び出します。メソッドはデータと振る舞いをカプセル化し、オブジェクト指向プログラミングを実現します。
中級構造体
問題50: 関連関数
関連関数は構造体に属するがselfパラメータを持たない関数で、主にコンストラクタとして使われます。Self型は実装している型自身を指し、返り値や型名として使えます。new、from、defaultなどの命名で、目的に応じたコンストラクタを複数定義できます。Rustの慃習的なインスタンス作成方法です。
中級ジェネリクス
問題51: ジェネリック型
ジェネリック型を使うと、複数の型に対して動作する構造体や関数を定義できます。'<'T'>'のように山括弧で型パラメータを指定し、使用時に具体的な型が決まります。implブロックでも同様に型パラメータを宣言します。コードの再利用性が高まり、型安全性を保ちながら柔軟なプログラムが書けます。
中級構造体
問題52: タプル構造体とユニット構造体
タプル構造体は名前付きフィールドを持たない構造体で、要素には.0、.1のようにアクセスします。newtypeパターンは既存の型をラップして新しい型を作る技法で、型安全性を高めます。ユニット構造体はフィールドを持たない構造体で、マーカーやフラグとして使われます。
中級エラー処理
問題53: panic!マクロ
panic!は回復不可能なエラーでプログラムを停止させます。予期しない状態や続行不可能な場合に使用します。assert!は条件が偽の場合にpanic!し、debug_assert!はデバッグビルドでのみ有効です。エラーメッセージを指定してデバッグを容易にします。通常はResultを使い、panic!は最終手段です。
中級エラー処理
問題54: Result型の活用
Result型の値を取り出す方法は複数あります。unwrapは成功時の値を取り出し、失敗時はpanic!。expectはカスタムメッセージ付き。unwrap_orはデフォルト値を指定して安全に処理。matchで明示的に両方のケースを扱うのが最も安全です。状況に応じた適切な方法を選びましょう。
中級エラー処理
問題55: ?演算子
?演算子はResultやOptionのエラー伝播を簡潔にします。失敗時は早期リターン、成功時は値を取り出します。複数の可能なエラーを連鎖的に扱う際に便利で、コードが読みやすくなります。関数の返り値はResultまたはOptionである必要があります。エラー型の変換にはmap_errを使います。
中級エラー処理
問題56: match式でのエラー処理
match式はResult型のエラー処理に最適で、OkとErrを明示的に処理できます。エラーの詳細情報を取り出し、種類ごとに異なる処理が可能です。kind()メソッドでエラーの種類を判別し、適切なメッセージや回復処理を実装できます。網羅性を保証し、全エラーケースを処理します。
中級エラー処理
問題57: カスタムエラー型
独自のエラー型を定義することで、アプリケーション固有のエラーを表現できます。Fromトレイトを実装すると、?演算子で自動変換されます。複数のエラー源を統一的に扱え、エラー処理がシンプルになります。enumで様々なエラーケースを分類し、適切な情報を保持できます。
中級エラー処理
問題58: unwrap_or系メソッド
OptionやResultの値を安全に取り出すメソッド群です。unwrap_orはデフォルト値を直接指定、unwrap_or_elseはクロージャで動的に生成。map_orは変換とデフォルト値を組み合わせます。ok_orはOptionをResultに変換。これらはpanic!を避けて安全に処理します。
中級エラー処理
問題59: map系メソッド
mapはOptionやResultの中身を変換します。成功値を変換するmap、エラーを変換するmap_errがあります。元のコンテナ構造(Some/None、Ok/Err)は保持され、中身だけが変換されます。メソッドチェーンで連続的に変換でき、関数型プログラミングの基礎です。
中級エラー処理
問題60: and_then(フラットマップ)
and_thenはOption/Resultを返す関数をチェインします。mapと違い、入れ子にならずフラット化されます。複数の可能な失敗を連鎖的に処理でき、モナディックな操作の一種です。エラー処理をシンプルに保ちながら、複雑なビジネスロジックを表現できます。
中級エラー処理
問題61: エラーの集約
複数のResultを集約して処理する方法です。collectはイテレータのResultをResultのコレクションに変換し、一つでもエラーがあればErrを返します。partitionで成功と失敗を分離できます。バッチ処理や検証処理で重要なパターンです。
中級エラー処理
問題62: From/Intoトレイトでのエラー変換
Fromトレイトを実装すると、?演算子で自動的にエラー型が変換されます。複数のエラー源を統一的に扱え、コードが簡潔になります。Fromを実装するとIntoも自動的に実装されます。エラー処理の柔軟性と統一性を向上させる重要なパターンです。
中級トレイト
問題63: トレイトの定義
トレイトは共通の振る舞いを定義するインターフェースです。traitキーワードで定義し、メソッドシグネチャを含みます。デフォルト実装を提供でき、実装者の負担を軽減します。ポリモーフィズムを実現し、柔軟で再利用可能なコードを書けます。
中級トレイト
問題64: トレイトの実装
既存の型に標準ライブラリのトレイトを実装できます。Displayで表示形式を定義、Addで演算子オーバーロードを実現します。孤児ルールにより、外部クレートの型とトレイトの組み合わせには制限があります。型に新しい機能を追加する強力な方法です。
中級トレイト
問題65: デフォルト実装
トレイトはメソッドのデフォルト実装を提供でき、実装者の負担を軽減します。トレイトを実装する際、デフォルト実装をそのまま使うか、独自の実装でオーバーライドできます。柔軟なインターフェースを作りながら、実装をシンプルに保てます。柔軟性と利便性のバランスを取る強力な機能です。
中級トレイト
問題66: トレイト境界
トレイト境界はジェネリック型を制約し、特定の機能を持つことを保証します。山括弧内でT: Traitと書くか、where句で複雑な制約を表現します。型安全性を保ちながら、特定のメソッドを使用できるジェネリック関数を書けます。Rustの型システムの中核機能です。
中級トレイト
問題67: Deriveマクロ
#[derive]属性で一般的なトレイトを自動実装できます。Debugは{:?}での表示、Cloneはコピー作成、PartialEqは等価比較を可能にします。ボイラープレートコードを削減し、一貫した実装を保証します。フィールドがトレイトを実装していれば、再帰的に動作します。
中級トレイト
問題68: Display/Debugトレイト
DisplayとDebugは型を文字列に変換するフォーマット用トレイトです。Displayは{'}でユーザー向けの出力、Debugは{:?}で開発者向けの出力を提供します。Displayを実装すると型を直接出力でき、Debugは内部構造を表示してデバッグに役立ちます。型を表示可能にする基本的なトレイトです。
中級ライフタイム
問題69: ライフタイム注釈
ライフタイム注釈は参照の有効期間を明示的に指定します。'aという記法は、同じライフタイムを持つすべての参照が同じ期間有効であることを示します。ダングリング参照を防ぎ、コンパイル時にメモリ安全性を保証します。コンパイラはこれらの注釈を使って参照がデータより長生きしないことを検証します。
中級ライフタイム
問題70: 構造体のライフタイム
参照を含む構造体はライフタイムパラメータが必要で、参照が有効であることを保証します。ライフタイムパラメータ'aは構造体が参照されたデータより長生きしないことを示します。構造体フィールドのダングリング参照を防ぎます。implブロックでも一貫性を保つためライフタイムパラメータが必要です。
中級ライフタイム
問題71: ライフタイム省略規則
Rustはライフタイム省略規則により明示的な注釈を減らします。規則1:各入力参照は独自のライフタイムを得る。規則2:入力ライフタイムが1つなら、すべての出力に割り当てられる。規則3:メソッドでは&selfのライフタイムが出力に割り当てられる。これらの規則により安全性を保ちながらコードが簡潔になります。
中級ライフタイム
問題72: staticライフタイム
'staticはプログラム全体の期間続く特別なライフタイムです。文字列リテラルはプログラムバイナリに格納されるため'staticライフタイムを持ちます。グローバル定数やstaticも'staticライフタイムを持ちます。どのスコープよりも長生きする必要があるデータに有用です。Rustで最も長いライフタイムです。
中級トレイト
問題73: トレイトオブジェクト
トレイトオブジェクトはdynキーワードを使った動的ディスパッチを可能にします。同じトレイトを実装する異なる型をコレクションに格納できます。実行時ポリモーフィズムは小さなパフォーマンスコストがありますが柔軟性を提供します。Box'<'dyn Trait'>'でヒープにトレイトオブジェクトを格納するのが一般的です。
中級ジェネリクス
問題74: ジェネリックトレイト
ジェネリックトレイトは型パラメータを受け取り、柔軟なインターフェースを実現します。関連型と異なり、ジェネリックトレイトは異なる型パラメータで複数の実装が可能です。コンテナ、変換器、様々な型で動作する操作に有用です。違いを理解することで、APIデザインに適切な抽象化を選択できます。
中級クロージャ
問題75: クロージャ基礎
クロージャは環境をキャプチャできる無名関数です。||構文でクロージャを作成し、オプションでパラメータを指定できます。変数を参照、可変参照、値でキャプチャできます。コールバック、イテレータ、関数型プログラミングパターンに強力です。Rustは安全性と効率性のためキャプチャモードを推論します。
中級クロージャ
問題76: クロージャの型
クロージャは変数のキャプチャ方法によってFn、FnMut、FnOnceトレイトを実装します。Fnは不変借用、FnMutは可変借用、FnOnceは所有権を取ります。moveキーワードは所有権キャプチャを強制します。これらのトレイトの理解は、関数へのクロージャ渡しや構造体への格納に重要です。
中級データ構造
問題77: イテレータメソッド
イテレータはデータ変換のための強力なメソッドを提供します。mapは各要素を変換し、filterは条件に基づいて要素を選択し、foldは値を累積します。メソッドチェーンにより関数型プログラミングパターンが可能になり、コードがより表現力豊かで簡潔になります。これらのメソッドは遅延評価され、collectなどの終端操作で実行されます。
中級データ構造
問題78: collectメソッド
collect()はイテレータをコレクションに変換する強力なメソッドです。Vec、HashMap、String、さらにはResult/Optionも作成できます。collectは戻り値の型に対してジェネリックなため、型注釈がしばしば必要です。FromIteratorトレイトがこの柔軟性を可能にします。collectの理解はデータ変換のためのイテレータの可能性を解放します。
中級データ構造
問題79: カスタムイテレータ
Iteratorトレイトを実装してカスタムイテレータを作成します。トレイトはItem型とnext()メソッドの定義が必要です。next()は値がある限りSome(value)を返し、尽きたらNoneを返します。カスタムイテレータは標準のイテレータメソッドとシームレスに統合されます。このパターンはシーケンス生成、データ解析、ドメイン固有の反復に便利です。
中級スマートポインタ
問題80: スマートポインタ - Box
Box'<'T'>'は値をスタックではなくヒープに配置するスマートポインタです。無限サイズになる再帰的な型に必須です。Boxはヒープデータの所有権を提供し、スコープを抜けると自動的に解放します。他のスマートポインタと違い、実行時オーバーヘッドがゼロで、大きなデータやコンパイル時にサイズが必要な場合に便利です。
中級スマートポインタ
問題81: スマートポインタ - Rc
Rc'<'T'>'(参照カウント)は同じデータの複数所有を可能にします。参照数を追跡し、カウントがゼロになると解放します。Rc::cloneで新しい参照を作成 - カウントを増やすだけでディープコピーしません。Rcはシングルスレッド専用で、マルチスレッドにはArcを使用。共有不変データ構造に最適です。
中級スマートポインタ
問題82: RefCell
RefCell'<'T'>'は内部可変性を提供 - 不変な値を可変にできるパターンです。コンパイル時ではなく実行時に借用ルールを強制します。borrow()で不変アクセス、borrow_mut()で可変アクセス。RcとRefCellを組み合わせると複数の所有者が共有データを変更できます。借用ルール違反でパニックします。
中級パターンマッチング
問題83: パターンマッチング応用
Rustのパターンマッチングは'if'を使ったガード節や@バインディングで強化できます。ガードはパターンに条件を追加し、パターンと条件の両方が真の場合のみマッチします。@バインディングはパターンをテストしながら値全体をキャプチャします。これらの機能により複雑なロジックのための柔軟で表現力豊かなパターンマッチングが可能です。
中級パターンマッチング
問題84: if let と while let
'if let'と'while let'は単一のパターンだけを気にする場合の簡潔な構文を提供します。'if let'はオプションのelse分岐を持つ単一パターンのチェックに最適です。'while let'はパターンが失敗するまで繰り返しマッチし、イテレータの消費やシーケンス処理に便利です。完全なmatch式と比べて定型文を削減します。
中級ジェネリクス
問題85: 型エイリアス
型エイリアスは'type'キーワードを使って既存の型に新しい名前を作成します。複雑な型シグネチャを簡略化し、コードの可読性を向上させます。特に長いジェネリック型、関数ポインタ、固定エラー型のResultに便利です。newtypeパターンと違い、エイリアスは新しい型を作らず別名だけです。ジェネリックエイリアスも可能です。
上
上級
無料で学習可能
上級並行性
問題86: スレッドの基礎
Rustは所有権システムを通じて安全な並行性を提供します。thread::spawnは並行に実行される新しいスレッドを作成します。joinメソッドはスレッドの終了を待機し、結果を返します。スレッドは作成スコープより長生きする可能性があるため、moveキーワードで変数をスレッドに移動します。これによりデータ競合なしのメモリ安全性が保証されます。
上級並行性
問題87: メッセージパッシング
メッセージパッシングはRustが推奨する並行性アプローチです:「メモリを共有して通信するのではなく、通信してメモリを共有する」。mpsc(複数生産者、単一消費者)チャネルはスレッド間で安全にメッセージを送信します。所有権はチャネルを通じて移動し、スレッド安全性を保証。受信者は全送信者がドロップされるまでメッセージを反復処理できます。
上級並行性
問題88: Arc(Atomic Rc)
Arc(アトミック参照カウント)は複数のスレッドが同じデータの所有権を共有できます。Rcと違い、Arcはスレッド安全のためアトミック操作を使用。Arcは不変アクセスのみ許可し、変更にはMutexと組み合わせます。参照カウントはアトミックに更新され、スレッド間で安全です。Arc::cloneは安価でアトミックカウンタを増やすだけです。
上級並行性
問題89: Mutex
Mutex(相互排他)は一度に一つのスレッドだけがデータにアクセスできるよう保証します。lock()メソッドはデータへのアクセスを提供するMutexGuardを返します。ガードはドロップ時に自動的にロックを解放。try_lock()はブロックせずに取得を試みます。スレッドがロック保持中にパニックすると、データ破損を防ぐためMutexは「汚染」されます。
上級並行性
問題90: RwLock
RwLock(読み書きロック)は複数の読み取りまたは一つの書き込みを許可します。複数のスレッドが同時に読み取りロックを保持できますが、書き込みロックは排他的です。読み取りが書き込みより多い場合にパフォーマンスが向上。read()は読み取りロック、write()は書き込みロックを取得。Mutex同様、非ブロッキングのtry_バリアントもあります。
上級並行性
問題91: Condvar(条件変数)
Condvarはスレッドが条件を待機し、互いに通知し合うことを可能にします。Mutexと組み合わせてスレッド実行を調整。wait()はMutexを解放して通知までブロックし、その後ロックを再取得。notify_one()は一つの待機スレッドを起床、notify_all()は全てを起床。プロデューサーコンシューマーパターンやスレッド同期に不可欠です。
上級並行性
問題92: Send と Sync
SendとSyncはスレッド安全性のマーカートレイトです。Send型はスレッド間で移動可能、Sync型はスレッド間で共有可能です。ほとんどの型はこれらを自動実装します。RcはSendでもSyncでもなく、Arcは両方です。これらのトレイトの理解は並行コードの記述に重要で、コンパイル時にスレッド安全性を保証します。
上級並行性
問題93: async/await基礎
async/awaitはRustで非同期プログラミングを可能にします。async関数は計算を表すFutureを返します。awaitはFutureが完了するまで実行を一時停止します。これにより同期的に見える非同期コードが書けます。Futureは遅延評価され、ポーリングされるまで実行されません。asyncコードの実行にはtokioのようなエグゼキュータが必要です。
上級並行性
問題94: tokioランタイム
tokioはRustで最も人気の非同期ランタイムです。Futureのエグゼキュータと非同期ユーティリティを提供。#[tokio::main]はasync main用のランタイムを作成。spawnは独立して実行される並行タスクを作成します。tokio::timeは非同期タイマーと遅延を提供。ランタイムはタスクスケジューリング、I/O、タイマーを効率的に管理します。
上級並行性
問題95: 非同期ストリーム
ストリームはイテレータの非同期版です。時間の経過とともに到着するデータを効率的に処理できるよう、値を非同期に生成します。tokio_streamはmap、filter、collectなどの馴染み深いメソッドを持つStreamExtトレイトを提供。ストリームはネットワークデータ、ファイルI/O、その他の非同期ソースの処理に不可欠です。async/awaitパターンとよく組み合わせられます。
上級ジェネリクス
問題96: 関連型
関連型はトレイト内で型プレースホルダを定義します。ジェネリックパラメータと異なり、呼び出し側ではなく実装側が決定します。実装ごとに論理的な型が一つしかない場合、より整理されたAPIを作成します。関連型は型パラメータの増殖を減らし、トレイト境界をより読みやすくします。Iterator、Future、その他の標準トレイトでよく使用されます。
上級ジェネリクス
問題97: ファントム型
PhantomDataは構造体フィールドに現れない型パラメータの使用を可能にします。これによりコンパイル時に型が不変条件を強制する型レベルプログラミングが可能になります。一般的な用途には単位型、状態マシン、ライフタイム変性があります。PhantomDataは実行時コストがゼロで、純粋に型システムのためのものです。このパターンは型安全性により非互換な値の混合を防ぎます。
上級ジェネリクス
問題98: 型状態パターン
型状態パターンはRustの型システムを使ってコンパイル時に状態マシンをエンコードします。無効な状態遷移は実行時バグではなくコンパイルエラーになります。各状態は異なる型で、メソッドは適切な状態でのみ利用可能です。このパターンはプロトコルが正しく守られることを保証し、バグのクラス全体を排除します。ビルダーパターンやネットワークプロトコルで広く使用されます。
上級ライフタイム
問題99: 高階トレイト境界
高階トレイト境界(HRTB)はすべての可能なライフタイムに対する制約を表現できます。for'<''a'>'構文はライフタイムに対する全称量化を作ります。これは特定の一つではなく、任意のライフタイムで動作する関数に不可欠です。クロージャ境界やイテレータアダプタで一般的。HRTBは任意のライフタイムの借用データで動作する柔軟なAPIを可能にします。
上級ジェネリクス
問題100: GATs(ジェネリック関連型)
ジェネリック関連型は関連型がライフタイムや型に対してジェネリックになることを可能にします。これにより貸与イテレータや非同期トレイトのようなより強力な抽象化が可能になります。GATsは単純な関連型と完全なジェネリックパラメータのギャップを埋めます。ゼロコスト抽象化を維持しながら型間の複雑な関係を表現するのに重要です。Rust 1.65で安定化されました。
上級高度な型
問題101: constジェネリクス
constジェネリクスはコンパイル時定数を型パラメータとして使用できる機能です。配列サイズや数値定数を型レベルで抽象化でき、ゼロコストで柔軟な型を作成できます。従来は特定のサイズ([T; 32]など)ごとに実装が必要でしたが、constジェネリクスにより任意のサイズに対応可能。コンパイル時に全てが解決されるため、実行時オーバーヘッドはありません。
上級高度な型
問題102: Newtypeパターン応用
Newtypeパターンは既存の型を新しい型でラップし、型安全性を向上させます。タプル構造体で実装され、内部値へのゼロコストアクセスを提供。異なる単位や意味を持つ値を型レベルで区別でき、誤った使用をコンパイル時に防ぎます。トレイト実装により演算子オーバーロードや型変換を定義でき、直感的なAPIを構築できます。
上級高度なパターン
問題103: ビルダーパターン
ビルダーパターンは複雑なオブジェクトを段階的に構築する設計パターンです。メソッドチェーンで流暢なAPIを提供し、必須・オプショナルフィールドを型安全に扱えます。各メソッドはselfを消費して返すため、不変性を保ちながら状態を更新。build()メソッドで検証を行い、エラーハンドリングも組み込めます。Rustの所有権システムと相性が良いパターンです。
上級システムプログラミング
問題104: unsafe基礎
unsafeは厳密に必要な場合のみ使用する強力な機能です。生ポインタ(*const T、*mut T)は借用チェッカーを迂回し、nullや無効なメモリを指す可能性があります。unsafeブロック内でのみデリファレンス可能。安全性の保証は開発者の責任となり、メモリ安全性、データ競合の防止、有効なポインタの保証が必要です。システムプログラミングやFFIで使用されますが、可能な限り安全な抽象化でラップすべきです。
上級システムプログラミング
問題105: FFI(Foreign Function Interface)
FFIはRustと他言語(主にC)の相互運用を可能にします。extern "C"ブロックで外部関数を宣言し、標準Cライブラリの関数を直接呼び出せます。#[no_mangle]はRustの名前マングリングを無効化し、Cから呼び出し可能な関数を作成。外部関数の呼び出しは常にunsafeです。ABI(Application Binary Interface)の違いに注意が必要。既存のCライブラリの活用やシステムAPIの呼び出しに不可欠です。
上級マクロ
問題106: 宣言的マクロ基礎
macro_rules!はコンパイル時にコードを生成する宣言的マクロを定義します。パターンマッチングによる柔軟な構文変換が可能。$で始まるメタ変数でパラメータを受け取り、:identは識別子、:exprは式などの型を指定。$()*は繰り返しパターンで可変長引数を処理。DRY原則に従い、ボイラープレートコードを削減します。Vec!やprintln!など標準ライブラリでも広く使用される強力な機能です。
上級マクロ
問題107: 宣言的マクロ応用
宣言的マクロの高度な技法として、再帰的パターンマッチングと可変長引数処理があります。マクロは自分自身を呼び出して再帰的に展開でき、リストや繰り返し構造を処理できます。$()+や$()*の繰り返しパターンで任意数の引数を受け取り、ttマンチャー(トークンツリー操作)で複雑な構文変換を実現。コンパイル時に全て展開されるため実行時オーバーヘッドなし。標準ライブラリのvec!マクロなどがこれらの技法を活用しています。
上級マクロ
問題108: 手続きマクロ入門
手続きマクロはRustコードとして実行され、コンパイル時にASTを操作します。proc_macro crateで定義し、TokenStreamを入出力とします。カスタムderiveは最も一般的な用途で、#[derive(MyTrait)]で自動的にトレイト実装を生成。synでASTを解析し、quoteで新しいコードを生成します。宣言的マクロより強力で、任意の計算やファイルI/Oも可能。serdeやdieselなど多くのcrateがこの機能を活用しています。
上級マクロ
問題109: 属性マクロ
属性マクロは関数、構造体、モジュールに付与してコードを変換します。#[proc_macro_attribute]で定義し、属性引数と装飾対象の両方を受け取ります。関数の前後にログ出力を追加したり、自動的にベンチマークコードを生成するなど、アスペクト指向プログラミングが可能。tokioの#[main]やtestの#[test]が代表例。メタプログラミングの強力な手法で、ボイラープレートを削減し、横断的関心事を分離できます。
上級システムプログラミング
問題110: ビルドスクリプト
build.rsはCargoのビルド前に実行される特別なスクリプトです。コンパイル時のコード生成、環境変数の設定、ネイティブライブラリのリンクなどを行います。OUT_DIR環境変数で指定されたディレクトリに生成ファイルを配置し、include!マクロで取り込みます。cargo:rerun-if-changedでビルドスクリプトの再実行条件を制御。ビルド時情報の埋め込み、バインディング生成、条件付きコンパイルなど、ビルドプロセスをカスタマイズする強力な機能です。