Rust は、非常に高速で、セグメンテーション違反を防ぎ、スレッドセーフなシステム プログラミング言語です。これらの機能により、Rust はシステム プログラミングのための強力なツールになりますが、他の言語の人には馴染みのないいくつかの新しい概念も導入されます。
この包括的なガイド「The Hard Things About Rust」では、Rust のこれらの困難な側面に光を当て、初心者と経験豊富なプログラマーの両方が理解できるようにすることを目的としています。これらの複雑な概念に光を当て、理解を深めるために具体的な例と現実世界のシナリオを使って各概念を説明します。
ここで取り上げる内容は次のとおりです。
-
所有権: Rust における所有権の基本的な概念から始めます。値を所有するとはどういう意味なのか、所有権がどのように転送されるのか、Rust の所有権モデルがメモリ管理にどのように役立つのかを見ていきます。
-
借用とライフサイクル: 所有権の基礎に基づいて、データを安全に参照できるようにする 2 つの相互関連する概念である借用とライフサイクルについて詳しく説明します。
-
スライシング: メモリのチャンクのビューであり、データに効率的にアクセスするために Rust で広く使用されているスライスについてわかりやすく説明します。
-
エラー処理: Rust のエラーに対するアプローチはユニークかつ堅牢です。
Result
エレガントなエラー処理のための とそのOption
種類、およびその使用方法を紹介します。 -
同時実行性: Rust の強力で洗練された同時実行性モデルについて詳しく説明します。スレッド、メッセージパッシング、共有状態の同時実行性などについて説明します。
-
高度な型と特性
Box
: 、Rc
、 など、Rust の高度な型のいくつかを検討しますArc
。特性と特性オブジェクトについても紹介します。 -
Async/Await と Futures : 高度な概念に進むにつれて、Rust の async/await 構文と非同期プログラミングを処理するための Futures モデルについて説明します。
このガイドの目的は、これらのトピックの概要を提供するだけではなく、これらの概念の背後にある理論的根拠、舞台裏でどのように機能するか、Rust プログラムでそれらを効果的に使用する方法を理解できるようにすることです。
Rust 言語をさらに深く掘り下げたいと考えている Rust 初心者であっても、これらの複雑な概念の理解を深めたいと考えている中級 Rustacean であっても、このガイドはあなたのためのものです。Rust の困難を克服する旅に出かけましょう!
所有
所有権はRustの基本的な概念です。これはメモリ安全性に対する Rust のアプローチの一部であり、Rust をプログラミング言語の中でユニークなものにしています。借用やライフタイムなどの他の多くの Rust 概念がその上に構築されているため、所有権を理解することは Rust プログラムを作成する上で非常に重要です。
所有権とは何ですか?
Rustでは、すべての値にownerと呼ばれる変数があります。所有者は一度に 1 人だけです。所有者がスコープ外になると、値は削除またはクリーンアップされます。
簡単な例を考えてみましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"hello world"</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// s is the owner of the &str "hello world"</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-comment-color)">// s goes out of scope here, and the string is dropped</span>
</code></span></span>
上記のコードでは、変数はs
string の所有者です"hello world"
。s
ブロックの終わりで範囲外になると、文字列は削除され、そのメモリが解放されます。
モバイルの所有権
Rustでは、代入演算子は、=
ある変数から別の変数に所有権を移します。=
これは、値をコピーする他の言語とは異なります。
次の例を考えてみましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
上記のコードでは、s1
string は最初は owner です "hello"
。ただし、回線はlet s2 = s1;
所有権を から に移転しs1
ますs2
。現在、s2
は文字列の所有者であり"hello"
、s1
無効になっています。その後 を使用しようとすると、 Rust はコンパイル時にエラーを返しますs1
。
コピー特性
Rust の特定の型はこのCopy
特性を実装しています。このような型が別の変数に割り当てられると、所有権は移動されませんが、値のコピーが作成されます。すべての整数および浮動小数点型、ブール型、文字型、および特性を実装する型タプルはCopy
ですCopy
。
以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">y</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
上記のコードでは、x
はトレイトを実装する整数ですCopy
。したがって、 を書いたときに所有権は移動しませんlet y = x;
。代わりに、値x
を からにコピーしますy
。
なぜ所有権があるのでしょうか?
所有権の概念により、Rust はガベージ コレクターを必要とせずにメモリの安全性を保証できます。Rust は、値の所有者は 1 人だけであること、および所有者がスコープ外に出ると値がクリアされることを強制することで、null ポインターやダングリング ポインター、二重解放、データ競合などの一般的なプログラミング エラーを防止します。
借用とライフタイム: Rust でのデータの安全な参照
借用とライフタイムは、Rust の最も注目すべき機能の 2 つです。これらを組み合わせることで、Rust はガベージ コレクターなしでメモリセーフおよびスレッドセーフになることができます。これらの概念を詳しく見てみましょう。
ローン
Rust では、コードの他の部分が所有権を取得せずに値にアクセスできるようにすることがよくあります。これは「借入」と呼ばれる機能を通じて行われます。借入には、共有借入と可変借入の 2 種類があります。
共有借入
共有借用により、アイテムに複数の参照を含めることができます。これはRustのシンボルを使用し&
て行われます。例を見てみましょう:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">len</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">calculate_length</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"The length of '{}' is {}."</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">len</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">calculate_length</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">usize</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-name-color)">.len</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
このコードでは、一時的に使用するcalculate_length
ために借用していますs1
。s1
はまだmain
関数に属しているため、呼び出しs1
後に再度使用できますcalculate_length
。
可変借用
可変借用は、借用した値の変更を許可したい場合に使用します。&mut
これは、変数の前に を使用して実行されます。例えば:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">change</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">change</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-name-color)">.push_str</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">", world"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ここでのchange
関数は借用しs1
て変更することです。これが可能なのは、s1
変更可能な借用があるためです。
ただし、Rust には、1 つの変更可能な参照または任意の数の不変更な参照を持つことができますが、両方を持つことはできないというルールがあります。このルールにより、データ競合が決して発生しないことが保証されます。
コード例を使用してこの概念を詳しく説明しましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// no problem</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// no problem</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{} and {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// r1 and r2 are no longer used after this point</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r3</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// no problem</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r3</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
r1
この例では、 と は作成時にはスコープ内にありますが、r2
作成後には使用されr3
ないため、コードは正常に機能します。r3
Rust のルールでは、(前に述べたように) 1 つの可変参照または任意の数の不変参照を持つことができますが、両方を持つことはできないと規定されていますが、これは参照を使用する場合にのみ適用されます。
ここで、Rust の借用ルールに違反する例を見てみましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// no problem</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// no problem</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">r3</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// PROBLEM! // cannot borrow `s` as mutable because it is also borrowed as immutable</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{}, {}, and {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r3</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この場合r1
、 と があり、r2
これらは不変参照であり、r3
どちらも変更可能参照です。これらすべてを同時に使用しようとしていますが、これは Rust の借用ルールに違反するため、コンパイラはエラーをスローします。
このルールにより、コンパイル時のデータ競合が防止されます。
人生
ライフサイクルは、すべての借用が有効であることを保証する Rust の方法です。ライフサイクルのポイントは、ダングリング参照を防ぐことです。ダングリング参照は、データへの参照があり、そのデータが参照の前に削除される場合に発生します。
Rust では、コンパイラはライフタイムを使用して、そのようなエラーが発生しないようにします。以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-text-color)">longest</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">'a</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">'a</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">'a</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">'a</span> <span style="color:var(--syntax-text-color)">str</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-name-color)">.len</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-name-color)">.len</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">x</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">y</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この関数では、'a
は次のようなライフタイム パラメータです。 あるライフタイム に対して'a
、少なくとも と同じ長さの文字列のスライスである 2 つの引数を受け取り'a
、少なくとも と同じ長さの文字列のスライスを返します'a
。
これは少し抽象的なので、具体的な例を考えてみましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">string1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"long string is long"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">string2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"xyz"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">result</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">longest</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">string1</span><span style="color:var(--syntax-name-color)">.as_str</span><span style="color:var(--syntax-text-color)">(),</span> <span style="color:var(--syntax-text-color)">string2</span><span style="color:var(--syntax-name-color)">.as_str</span><span style="color:var(--syntax-text-color)">());</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"The longest string is {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">result</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ここで、 の存続期間はstring1
の存続期間よりも長いためstring2
、result
で使用される場合にprintln!
は参照されずstring2
、ダングリング参照がないことを確認します。
要約すると、借用とライフタイムは、Rust を安全かつ効率的にするための表裏の関係にあります。これらにより、Rust はコンパイル時の安全性と同時実行性を確保できます。これらを理解することがRustをマスターする鍵となります。
スライス: Rust のシーケンス ビュー
Rust は、コレクション全体ではなく、連続したシーケンスまたはコレクションの一部を参照する方法を提供します。これは「スライス」と呼ばれる機能で行われます。
スライスを理解する
スライスは、コレクション全体への参照ではなく、コレクションの 1 つ以上の連続した要素への参照を表します。スライスの例を次に示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello world"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">hello</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">world</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">6</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">11</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{} {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">hello</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">world</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
このコードでは、hello
と はworld
スライスですs
。数値 [0..5] と [6..11] は、「インデックス 0 から開始し、インデックス 5 まで継続する (インデックス 5 は含まない)」および「インデックス 6 から開始してインデックス 11 まで継続する (インデックス 11 は含まない)」ことを意味する範囲インデックスです。 「それぞれ。」このプログラムを実行すると、 が表示されますhello world
。
文字列スライス
文字列スライスは文字列の一部への参照であり、次のようになります。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hello world"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">hello</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">world</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">6</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">11</span><span style="color:var(--syntax-text-color)">];</span>
</code></span></span>
ここhello
で と はworld
文字列のスライスですs
。角括弧で囲まれた範囲を使用して [starting_index..ending_index] を指定することでスライスを作成できます。ここで、 はstarting_index
スライス内の最初の位置であり、ending_index
スライス内の最後の位置より 1 つ多い位置です。
配列スライス
文字列と同様に、配列もスライスできます。以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">slice</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{:?}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">slice</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ここで、は、配列の 2 番目と 3 番目の要素を含むslice
スライスになります。2, 3
a
スライスのメリット
スライスの利点は、シーケンスを新しいコレクションにコピーせずに、連続したシーケンスを参照できることです。これは、関数がコレクションの一部にアクセスするためのより効率的な方法です。
Rustでのエラー処理
エラー処理はあらゆるプログラミング言語の基本的な部分であり、Rust も例外ではありません。ソフトウェアの避けられないバグを認識し、それらに効率的に対処するための強力なメカニズムを提供します。Rust のエラー処理メカニズムの設計では、開発者がエラーを明示的に認識して処理する必要があるため、プログラムがより堅牢になり、多くの問題が実稼働環境に影響を与えるのを防ぐことができます。
Rust では、エラーを回復可能なエラーと回復不可能なエラーの 2 つの大きなカテゴリに分類します。回復可能なエラーは通常、存在しないファイルを開こうとするなど、通常は失敗する操作の結果として発生します。このような場合、通常はユーザーにエラーを通知し、操作を再試行するか、別の方法でプログラムを続行する必要があります。
一方、回復不可能なエラーは通常、境界外の配列にアクセスしようとしたなど、コード内のバグを示します。この種のエラーは、プログラムを直ちに停止する必要があるほど重大です。
興味深いことに、Rust は多くの言語で一般的なエラー処理メカニズムである例外を使用しません。代わりに、回復可能なエラーと回復不可能なエラーをそれぞれ処理するための 2 つの構造Result<T, E>
とpanic!
マクロが提供されます。
panic!
マクロ
Rust のマクロは、panic!
プログラムの実行を即時に停止するために使用されます。これは通常、プログラムが対処方法がわからない状況に遭遇した場合、または到達すべきではない状態に到達した場合に使用されます。これらのシナリオは通常、プログラムのバグを表します。呼び出されるとpanic!
、エラー メッセージが標準エラー出力に出力され、プログラムは終了します。
panic!
単純な文字列メッセージで呼び出すことも、 のような形式文字列で使用することもできます。println!
渡したメッセージはpanic!
緊急ペイロードとなり、プログラムがクラッシュした場合はエラー メッセージの一部として返されます。例えば:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">panic!</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-name-color)">panic!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"this is a terrible mistake!"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">panic!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"this is a {} {message}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"fancy"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">message</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"message"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">panic</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">panic_any</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// panic with the value of 4 to be collected elsewhere</span>
</code></span></span>
panic!
メインスレッドで呼び出された場合、他のすべてのスレッドが終了し、終了コードでプログラムが終了します101
。
Result<T, E>
列挙する
Rust の回復可能なエラーの処理方法は enums にカプセル化されていますResult<T, E>
。は、成功した結果とエラーのResult
2 つのバリアントを持つ汎用列挙型です。の利点はその明確な性質にあり、開発者は成功条件と失敗条件の両方を処理する必要があるため、エラー処理でよくある多くの落とし穴を回避できます。Ok(T)
Err(E)
Result
Rust にはResult
値を操作するいくつかの方法が用意されており、その中で最も有名なものは?
演算子です。?
return には演算子を付けることができますResult
。関数が成功して を返すとOk(T)
、?
演算子は値をアンラップしてT
プログラムを続行します。関数でエラーが発生して が返された場合Err(E)
、?
オペレータは直ちに現在の関数から戻り、エラーを呼び出しスタックに伝播します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">enum</span> <span style="color:var(--syntax-text-color)">Result</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">T</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">E</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">Ok</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">T</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-name-color)">Err</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">E</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この定義は、 を返す関数がResult
success( Ok
) で type の値を返すT
か、fail( Err
) で type のエラーを返すことができることを意味しますE
。
を返す関数の例を次に示しますResult
。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">num</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">ParseIntError</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">parse_number</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">Result</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ParseIntError</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">match</span> <span style="color:var(--syntax-text-color)">s</span><span style="color:var(--syntax-text-color)">.parse</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">Ok</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">Ok</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-name-color)">Err</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">Err</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">parse_number</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"42"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">match</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">Ok</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"The number is {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-name-color)">Err</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Error: {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">e</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、parse_number
文字列を整数に解析しようとします。成功した場合は 内の数値を返しOk
、そうでない場合は 内のエラーを返しますErr
。このmatch
ステートメントの処理には2 つの結果が考えられますResult
。
オプション
Enum はOption
に似ていますResult
が、関数が値を返すことができる場合、またはまったく返せない場合 (エラーの代わりに) に使用されます。それは次のように定義されます。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">enum</span> <span style="color:var(--syntax-text-color)">Option</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">T</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">Some</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">T</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">None</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
を返す関数の例を次に示しますOption
。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">find</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">array</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">],</span> <span style="color:var(--syntax-text-color)">target</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">Option</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">usize</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">index</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">array</span><span style="color:var(--syntax-name-color)">.iter</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-name-color)">.enumerate</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">item</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-text-color)">target</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">Some</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">index</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">None</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">array</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">match</span> <span style="color:var(--syntax-name-color)">find</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">array</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">Some</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">index</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Found at index {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">index</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">None</span> <span style="color:var(--syntax-declaration-color)">=></span> <span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Not found"</span><span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、find
関数は配列内の数値を検索しようとします。見つかった場合、関数は を返しますSome(index)
。ここで、 はindex
配列内の数値の位置です。見つからない場合、関数は を返しますNone
。
どちらResult
も、Option
これらの型を操作するためのさまざまな便利なメソッドを提供します。たとえば、or 内の値をunwrap
取得するために使用できますが、 is または the is の場合は混乱が発生します。より安全な代替手段として、それぞれデフォルト値またはフォールバック機能を提供するために使用できます。Ok
Some
Result
Err
Option
None
unwrap_or
unwrap_or_else
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Some</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">assert_eq!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">(),</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Option</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">u32</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">None</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-name-color)">assert_eq!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-name-color)">.unwrap_or</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">42</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-literal-color)">42</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Result</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">u32</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Err</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"emergency failure"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">assert_eq!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-name-color)">.unwrap_or_else</span><span style="color:var(--syntax-text-color)">(|</span><span style="color:var(--syntax-text-color)">_</span><span style="color:var(--syntax-text-color)">|</span> <span style="color:var(--syntax-literal-color)">42</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-literal-color)">42</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
一般に、Result
と は、Option
エラー処理と欠損値の表現のための Rust の強力なツールです。これらにより、コードで起こり得る失敗や null 条件がより明確になり、多くの一般的なプログラミング エラーの防止に役立ちます。
並行調査
Rust の同時実行性は、スレッド、メッセージ パッシング、共有状態などのいくつかのメカニズムを通じて実現されます。これらを順番に見ていきましょう。
1. スレッド
Rust には、std::thread
新しいスレッドを作成し、システムに依存しない方法でそれらを使用できるようにするモジュールがあります。新しいスレッドを作成する簡単な例を次に示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">spawn</span><span style="color:var(--syntax-text-color)">(||</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">10</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hi number {} from the spawned thread!"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from_millis</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">5</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hi number {} from the main thread!"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from_millis</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、新しいスレッドを作成し、thread::spawn
新しいスレッドの命令を含むクロージャをそれに渡します。メイン スレッドと新しいスレッドはメッセージを個別に出力し、各メッセージの間に 1 ミリ秒スリープします。
2. メッセージング
Rust は、Erlang 言語からインスピレーションを得たメッセージパッシング同時実行モデルを提供します。メッセージ パッシングは、スレッドまたはアクターがデータを含むメッセージを相互に送信することによって通信する同時実行性を処理する方法です。
Rustでは、このモジュールを使用してチャネルを作成できますstd::sync::mpsc
(mpscは複数のプロデューサー、単一のコンシューマーを表します)。以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">sync</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">mpsc</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">tx</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">rx</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">mpsc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">spawn</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">move</span> <span style="color:var(--syntax-text-color)">||</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">val</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"hi"</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">tx</span><span style="color:var(--syntax-name-color)">.send</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">val</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">received</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">rx</span><span style="color:var(--syntax-name-color)">.recv</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Got: {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">received</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、 でチャネルを作成しmpsc::channel
、トランスポート ( tx
) を新しいスレッドに移動します。このスレッドはメッセージ (「hi」) をチャネルに送信し、メインスレッドでそのメッセージを受信して出力するのを待ちます。
3. 共有状態
Rust は、ミューテックスを使用してスレッド間で安全な方法で状態を共有する方法も提供します。ミューテックスは相互排他を提供します。つまり、常に 1 つのスレッドだけがデータにアクセスできます。データにアクセスするには、スレッドはまずミューテックスのロックを要求することによって、アクセスが必要であることを通知する必要があります。以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">sync</span><span style="color:var(--syntax-text-color)">::{</span><span style="color:var(--syntax-text-color)">Mutex</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">counter</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">new</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Mutex</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">new</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">handles</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">vec!</span><span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">_</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">10</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">counter</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">clone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">counter</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">handle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">spawn</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">move</span> <span style="color:var(--syntax-text-color)">||</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">num</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">counter</span><span style="color:var(--syntax-name-color)">.lock</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">num</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">handles</span><span style="color:var(--syntax-name-color)">.push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">handle</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">handle</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">handles</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">handle</span><span style="color:var(--syntax-name-color)">.join</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Result: {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">counter</span><span style="color:var(--syntax-name-color)">.lock</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-name-color)">.unwrap</span><span style="color:var(--syntax-text-color)">());</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、ミューテックス内にカウンターを作成し、アトミック参照カウント (Arc) を使用してそれを複数のスレッド間で共有します。各スレッドはミューテックスをロックし、カウンターをインクリメントし、ロックを解放します。
これは高レベルの概要です。Rust の同時実行モデルは非常に強力で柔軟であり、同時実行コードがデータ競合やその他の一般的な同時実行の問題から解放されることを保証するための多くの機能を提供します。
高度なタイプと特性
箱
Box は、スタックではなくヒープに格納されているデータを指すスマート ポインターです。これらは、大量のデータを保存する場合、または特定の変数がメモリ内で移動しないようにしたい場合に便利です。
ボックスにも所有権があります。Box がスコープ外になると、デストラクターが呼び出され、ヒープ メモリが解放されます。
簡単な例を次に示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Box</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">new</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// b is a pointer to a heap allocated integer</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"b = {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Output: b = 5</span>
</code></span></span>
b
この例では、変数はヒープ上に整数を保持するボックスです。5
演算子は*
ボックスを逆参照し、ボックスが指す値を取得するために使用されます。
ラジコン
Rc は参照カウントを表します。これは、いつクリーンアップするかを決定する値への参照数を追跡することで、複数の所有者を許可するスマート ポインターです。rc は、プログラムの複数の部分で読み取られるデータをヒープ上に割り当てたい場合に使用されますが、コンパイル時にどの部分が最後にデータを使用したかを判断できません。
Rc はシングルスレッドのシナリオにのみ適用できることに注意してください。簡単な例を次に示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">rc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">Rc</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">original</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Rc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">new</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Rc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">clone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">original</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Rc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">clone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">original</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"original: {}, a: {}, b: {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">original</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Output: original: 5, a: 5, b: 5</span>
</code></span></span>
original
この例では、変数はヒープ上に整数を保持するRc です。5
この Rc の複数の「クローン」を作成できます (これらは実際には同じデータへの新しいポインターであり、完全なコピーではありません)。すべての Rc がスコープ外になると、ヒープ メモリが解放されます。
アーク
Arc はアトミック リファレンス カウンティングです。Rc と同じですが、マルチスレッドのコンテキストで安全に使用できます。Rc と同じ機能を提供しますが、参照カウントにアトミック操作を使用します。これにより、パフォーマンスが若干低下しますが、複数のスレッド間で安全に共有できます。
以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">sync</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">std</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">original</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">new</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">_</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">10</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">original</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Arc</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">clone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">original</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">thread</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">spawn</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">move</span> <span style="color:var(--syntax-text-color)">||</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">original</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、Arc を使用して、ヒープに割り当てられた整数を複数のスレッド間で共有します。各スレッドは Arc のクローン (データへの新しいポインター) を取得します。すべての Arc がスコープ外に出ると、ヒープ メモリが解放されます。
これらの型は、Rust でメモリとデータの所有権を管理するためのより高度な方法を提供し、より複雑なデータ構造とパターンを可能にします。ただし、複雑さも増し、正しく理解するのが難しくなるため、使用には注意が必要です。
特性
Rust では、トレイトは未知の型に対して定義されたメソッドのコレクションですSelf
。これらは、同じトレイトで宣言された他のメソッドにアクセスでき、共有または共通の動作を定義する方法です。特性は、型が実装できるインターフェイスを定義する方法であると考えてください。
次の簡単な例を考えてみましょう。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">trait</span> <span style="color:var(--syntax-text-color)">Animal</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">make_noise</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">self</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Dog</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Cat</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">impl</span> <span style="color:var(--syntax-text-color)">Animal</span> <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">Dog</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">make_noise</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">self</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">String</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Woof!"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">impl</span> <span style="color:var(--syntax-text-color)">Animal</span> <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">Cat</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">make_noise</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">self</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">String</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Meow!"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
上の例では、Animal
メソッド を使用してトレイトを定義しまし たmake_noise
。Dog
次に、この特性を合計構造体に実装しCat
、独自の機能バージョンを提供しますmake_noise
。これで、Animal
この特性を実装する任意の型でこの関数を呼び出すことができます。
フィーチャのクローンと複製
Rust は、特定の動作を伴う多数の事前定義された特性を提供します。そのうちの 2 つはClone
と のCopy
機能です。
このClone
機能により、データの明示的な複製が可能になります。clone
このメソッドは、型がそのClone
特性を実装している場合、型のデータの新しいコピーを作成するときに呼び出されます。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(Clone)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">p1</span><span style="color:var(--syntax-name-color)">.clone</span><span style="color:var(--syntax-text-color)">();</span> <span style="color:var(--syntax-comment-color)">// p1 is cloned into p2</span>
</code></span></span>
この例では、Point
構造体がトレイトを実装しているため、このメソッドを使用してClone
任意のインスタンスのコピーを作成できます。Point
clone
一方、このCopy
機能によりデータの暗黙的な複製が可能になります。これは、所有権を気にせずに値の浅いコピーを作成できるようにしたい場合に使用されます。型がCopy
特性を実装している場合、古い変数は代入後も引き続き使用できます。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(Copy,</span> <span style="color:var(--syntax-name-color)">Clone)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Simple</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Simple</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">10</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">s2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// s1 is copied into s2</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"s1: {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">s1</span><span style="color:var(--syntax-text-color)">.a</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// s1 is still usable</span>
</code></span></span>
この例では、特性Simple
が実装されており、コピーが可能であり、その後も使用可能です。Copy
s1
s2
ただし、すべてのタイプが機能するわけではないことに注意してくださいCopy
。String
ヒープ データを所有するカスタム構造など、リソースを管理する型はCopy
トレイトを実装できません。一般に、値を削除するときに型で特別な操作が必要な場合、それは実行できませんCopy
。この制限により、手動メモリ管理を行う言語でよくある問題である二重解放エラーが防止されます。
デバッグ機能
このDebug
機能は、通常はデバッグ目的で使用される出力構造データをフォーマットできます。デフォルトでは、Rust は構造体の値の出力を許可しません。ただし、Debug
特性が派生すると、println!
デバッグ形式 ( {:?}
) のマクロを使用して構造体の値を出力できます。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(Debug)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Rectangle</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">u32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">u32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">rect</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Rectangle</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">30</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">50</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"rect is {:?}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">rect</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
この例では、特性Rectangle
が派生されDebug
、その値を標準出力に出力できるようになります。
PartialEq と Eq トレイト
このPartialEq
特性により、型のインスタンスが等しいかどうかを比較できます。このEq
特性は に依存し、すべての比較が再帰的であること、つまり ifと、then である PartialEq
ことを示します。a == b
b == c
a == c
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(PartialEq,</span> <span style="color:var(--syntax-name-color)">Eq)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Are p1 and p2 equal? {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-text-color)">p2</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
この例では、インスタンスを比較できるように、および特性Point
が派生されます。PartialEq
Eq
Point
PartialOrd と Ord の特性
これらの特性は、型インスタンスに対する比較演算 ( <
、>
、<=
、>=
) をサポートします。PartialOrd
一部の値が比較できない場合がある場合は、部分的な順序付けが許可されます。一方、Ord
値間の完全な順序付けを実現できます。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(PartialOrd,</span> <span style="color:var(--syntax-name-color)">Ord,</span> <span style="color:var(--syntax-name-color)">PartialEq,</span> <span style="color:var(--syntax-name-color)">Eq)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Is p1 less than p2? {}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-text-color)">p2</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
この例では、、、および機能Point
がエクスポートされます。これにより、インスタンスを比較できるようになります。PartialOrd
Ord
PartialEq
Eq
Point
デフォルトの機能
このDefault
特性により、型のデフォルト値の作成が可能になります。default
型のデフォルト値を返す関数を提供します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-name-color)">#[derive(Default)]</span>
<span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">Point</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">y</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">i32</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">p1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Point</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">default</span><span style="color:var(--syntax-text-color)">();</span> <span style="color:var(--syntax-comment-color)">// Creates a Point with x and y set to 0</span>
</code></span></span>
この例では、フィーチャPoint
がエクスポートされますDefault
。Point
これにより、デフォルト値 (この場合は 0) でインスタンスを作成できます。
非同期/待機と先物
先物
Rust の A は、Future
まだ計算されていない可能性のある値を意味します。これらは、ノンブロッキング計算を可能にする同時プログラミングの概念です。プログラムは、遅い計算が完了するのを待たずに、他のタスクを続行できます。
Future は特性に基づいておりFuture
、その最も単純な形式は次のようになります。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">pub</span> <span style="color:var(--syntax-declaration-color)">trait</span> <span style="color:var(--syntax-text-color)">Future</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">Output</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">poll</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">self</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Pin</span><span style="color:var(--syntax-error-color)"><&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-declaration-color)">Self</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">cx</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-declaration-color)">mut</span> <span style="color:var(--syntax-text-color)">Context</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">Poll</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">Self</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">Output</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
このFuture
特性は の非同期バージョンですGenerator
。poll
これには、フューチャーを完了までプッシュするためにエグゼキューターによって呼び出されるメソッドがあります。このメソッドは、計算が完了したpoll
かどうかをチェックします。Future
その場合は返品してくださいPoll::Ready(result)
。そうでない場合は、戻り、Poll::Pending
現在のタスクをpoll
再び呼び出す必要があるときに通知されるように手配します。
非同期で待機する
async
await
Rust では処理のために使用されますが、これは作成方法と消費方法の 1つFutures
として考えることができます。async
Future
await
Future
async
は関数の前に置くと関数が 1 を返すようにするキーワードですFuture
。これは単純な非同期関数です:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">compute</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">i32</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-literal-color)">5</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
呼び出すと をcompute
返しFuture
、ドライバーが完了すると値を返します5
。
await
Future
が完了するまで現在の関数の実行を一時停止する方法です。以下に例を示します。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">compute_and_double</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">i32</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">compute</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-declaration-color)">.await</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">value</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">2</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
ここでは、実行が終了するまでcompute().await
実行が一時停止されます。完了すると、その戻り値を使用して関数が再開されます。compute_and_double
compute
compute
compute_and_double
関数が一時停止されている間await
、エグゼキュータは他の関数を実行できますFutures
。これが、Rust の非同期プログラミングで高い同時実行性を実現する方法です。つまり、複数のタスクを同時に実行し、タスクが I/O などの遅い操作を待機している間にタスク間を切り替えることになります。
執行者
実行者はタスクを完了まで推進する責任がありますFuture
。何が起こる必要があるかを説明しますFuture
が、実行者の仕事はそれを実現することです。つまり、遺言執行者がいないとFutures
何もできないのです。
block_on
クレートのエグゼキューターを使用した簡単な例を次に示しますfutures
。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">futures</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">executor</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-text-color)">block_on</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">hello</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-declaration-color)">-></span> <span style="color:var(--syntax-text-color)">String</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">String</span><span style="color:var(--syntax-text-color)">::</span><span style="color:var(--syntax-name-color)">from</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello, world!"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">fn</span> <span style="color:var(--syntax-name-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">future</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">hello</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-text-color)">result</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">block_on</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">future</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">println!</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"{}"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">result</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
この例では、block_on
a が取得されFuture
、現在のスレッドは a がFuture
完了するまでブロックされます。Future
その後、結果を返します。
Rust ではさまざまなエグゼキューターが利用可能であり、それぞれに異なる特徴があります。たとえばtokio
、高パフォーマンスの Web サービスを構築するために設計されたものもあります。たとえば、async-std
標準ライブラリのような非同期ユーティリティのセットを提供するものもあります。
開発者として、Futures
実行者が適切に完了までプッシュすることを確認するのはあなたの責任であることを忘れないでください。Future
aが完了せず、または完了まで進むことなく破棄された場合awaited
、それ自体をクリーンアップする機会はありません。
Rust のasync/await
構文とFuture
機能を総合すると、非同期コードを作成するための強力なモデルが提供されます。ただし、これらは複雑でもあり、言語の所有権と同時実行モデルを十分に理解する必要があります。
要約すれば、
Rust は、複雑なプログラミング タスク用の強力なツールセットを提供し、システム リソースに対する比類のない制御を提供します。これには高レベルの型、特性、および非同期関数が含まれており、低レベルと高レベルの両方のプログラミングのニーズを満たします。Rust は最初は恐ろしく思えるかもしれませんが、パフォーマンス、制御、安全性の面で Rust が提供する利点により、学ぶ旅は価値のあるものになります。所有権、借用、有効期間の概念を理解することは、Rust の複雑さをナビゲートする際のガイドとなります。これらの原則を受け入れることで、Rust プログラミングの最も困難な側面に取り組む準備が整います。コーディングを楽しんでください!