InfoWorld シニアライター |
Rust は、ガベージ コレクションなしで、マシン本来の速度で実行できるメモリ セーフなソフトウェアを記述する方法をプログラマーに提供します。また、習得が複雑な言語でもあり、初期の学習曲線はかなり急峻です。ここでは、Rust を使い始めるとき、そしてより熟練した Rust 開発者が注意すべき 5 つの落とし穴、障害、罠を紹介します。
所有権、借用、およびライフタイムは Rust に組み込まれています。これらは、ガベージ コレクションなしで言語がメモリの安全性を維持する方法の不可欠な部分です。
他の言語では、開発者に安全性やメモリの問題を警告しながらも、コードのコンパイルを許可するコード チェック ツールを提供しています。Rust はそのような動作をしません。借用チェッカー (Rust のコンパイラーの一部で、すべての所有権操作が有効であることを確認する部分) は、オフにできるオプションのユーティリティではありません。借用チェッカーに対して有効でないコードは、コンパイルされません。
借用チェッカーと戦わない方法については、1 つの記事全体を書くこともできます (書くべきかもしれません)。多くの一般的な動作に対してルールがどのように機能するかを確認するには、スコープに関する Rust by Example セクションを確認する価値があります。
Rust の旅の初期段階では、.clone() を使用してコピーを作成することで所有権の問題を回避できることを覚えておいてください。パフォーマンスが重要でないプログラムの部分では、コピーを作成しても測定可能な影響はほとんどありません。その後、ゼロコピーのパフォーマンスを最大限に高める必要がある部分に焦点を当て、プログラムのその部分で借用とライフタイムをより効率的にする方法を考えます。
変数名 _ (単一のアンダースコア) は、Rust では特別な動作をします。つまり、変数に受け取られる値は、その変数にバインドされません。通常、すぐに破棄される値を受け取るために使用されます。たとえば、何かが must_use 警告を発した場合、それを _ に割り当てるのがその警告を黙らせる一般的な方法です。
そのため、使用されているステートメントを超えて存続する値にはアンダースコアを使用しないでください。ここでは、スコープではなくステートメントについて話していることに注意してください。
注意すべきシナリオは、スコープ外になるまで何かを保持したい場合です。次のようなコードブロックがある場合
作成された文字列は、そのステートメントの後ですぐにスコープ外になります。つまり、ブロックの最後まで保持されません。(メソッド呼び出しは、コンパイル時に結果が省略されないようにするためのものです。)
この問題を回避する簡単な方法は、スコープの最後まで保持するが、それ以外にはあまり使用しない割り当てにのみ、_user や _item などの名前を使用することです。
この関数を、関数からの戻り値としてクロージャとして表現してみることもできます。
唯一の問題は、それが機能しないことです。コンパイラは、クロージャの入力と出力の有効期間が異なるため、有効期間が十分に長くない可能性があるというエラーを発します。
これを回避する 1 つの方法は、静的参照を使用することです。
別の関数を使用すると冗長になりますが、このような問題を回避できます。スコープがより明確になり、視覚的に解析しやすくなります。
注: このセクションの例は、Rust のライフタイムに関するよくある誤解についてのこの便利なリファレンスから引用したものです。
C++ と同様に、Rust では型のデストラクタを作成できます。これは、オブジェクトがスコープ外になったときに実行できます。ただし、必ず実行されるというわけではありません。
これは、特定のオブジェクトで借用期限が切れた場合にも当てはまります (おそらく 2 倍当てはまります)。何かで借用期限が切れても、そのデストラクタがすでに実行されていることを意味するわけではありません。実際、借用期限が切れたからといってデストラクタを実行したくない場合があります。たとえば、何かへのポインタを保持している場合などです。
Rust のドキュメントには、デストラクタが確実に実行されるようにするためのガイドラインと、デストラクタが確実に実行されるタイミングを知るためのガイドラインが記載されています。
キーワード unsafe は、生のポインターの逆参照などの操作を実行できる Rust コードにタグを付けるために存在します。これは Rust ではあまり頻繁に行う必要のない操作ですが (そうであることを願います!)、実行すると、まったく新しい潜在的な問題の世界が生まれます。
たとえば、安全でない操作によって生成された生のポインターを逆参照すると、無制限のライフタイムが発生します。安全でない Rust に関する書籍 Rustonomicon では、無制限のライフタイムは「コンテキストの要求に応じて大きくなる」と警告しています。つまり、当初必要だった、または意図していたものを超えて予期せず大きくなる可能性があるということです。
無制限の参照をどのように扱うかについて慎重に考えれば、問題はないはずです。しかし、安全のためには、関数のスコープ内でデリファレンスされたポインターを乱雑に扱うのではなく、関数内にデリファレンスされたポインターを配置し、関数の境界でライフタイムを使用する方がよいでしょう。
操作が Result を返す場合、それを処理する基本的な方法は 2 つあります。1 つは .unwrap() またはその類似関数 (.unwrap_or() など) を使用する方法です。もう 1 つは、Err 結果を処理するための本格的な match ステートメントを使用する方法です。
.unwrap() の大きな利点は、便利なことです。エラー状態が発生することが予想されないコード パス、またはエラー状態をどうせ処理できないコード パスの場合は、.unwrap() を使用して必要な値を取得し、処理を進めることができます。
これらすべてにはコストがかかります。エラー状態が発生するとパニックが発生し、プログラムが停止します。Rust のパニックは、プログラムに実際のバグがあることを示すほど何かが間違っていることを示す兆候であるため、回復不可能です。
.unwrap() または .unwrap() のバリアントの 1 つ (.unwrap_or() など) を使用する場合、エラー処理能力は依然として限られていることに注意してください。OK 値が生成する型に準拠する何らかの値を渡す必要があります。match を使用すると、適切な型の何かを生成するだけよりも、はるかに柔軟な動作が可能になります。
特定のプログラム パスでその柔軟性が必要になることはないと思われる場合は、.unwrap() で問題ありません。ただし、最初に完全な一致を記述して、処理の一部を見落としていないかどうかを確認することをお勧めします。
Serdar Yegulalp は InfoWorld のシニアライターであり、機械学習、コンテナ化、DevOps、Python エコシステム、定期レビューに重点を置いています。
著作権 © 2024 IDG Communications, Inc.
著作権 © 2024 IDG Communications, Inc.
元記事: https://www.infoworld.com/article/3715389/6-rust-programming-mistakes-to-watch-out-for.html