歴史的に、Rustの原則の一つは型の安全性を保証し、実行時エラーを引き起こす暗黙的な変換を避けることでした。しかし、コードの利便性のために、部分的な自動変換はderef coercionとFrom/Intoトレイトを通じて実現されており、参照やスマートポインタとともに使用できるユニバーサルAPIを簡素化しています。
問題は、自動的な型変換が混乱を引き起こす場合に発生します。例えば、&Stringを&strが期待されている場所に渡すと、隠れたDeref::derefが呼び出され、時折予期しない結果が生じることがあります(例えば、渡されるパラメータの型が変更された場合)。また、asを使用した明示的なキャストの問題もあります。
解決策:Rustは、スマートポインタ(Box、Rc、Arc)および文字列(&Stringから&str、&Vecから&slice)に関して厳密なderef-coercionの規則をコンパイラーレベルで実現しています。明示的な変換にはFrom、Into、TryFrom、TryInto、asトレイトが用意されており、基本的なキャストのためにあります。静的型付けと暗黙の変換を制限することで、エラーを避ける助けになります。
コード例:
fn print_text(text: &str) { println!("{}", text); } let s = String::from("Hello!"); print_text(&s); // s: String, &s: &String, &strへの自動変換
重要なポイント:
自分の型に対して手動でDerefを実装した場合、deref coercionは機能するか?
はい、自分の型に対してDerefトレイトを実装すれば、コンパイラは関数のシグネチャが期待する参照型に自動的に変換できるようになります。
値に対してderef coercionが発生することはあるか?
いいえ、自動的な間接参照は参照を渡す場合にのみ発生し、型がDerefを実装している時に限られます。
数値やenumを扱う際にasによる型変換にはどのような制限があるか?
asは安全性を保証しません。数値型間の変換はオーバーフローやデータの損失を引き起こす可能性があり、enumの場合は意味のない値(例えば、正しくないenumのバリアント)になる可能性があります。
初心者が&Stringを受け取る関数を作成し、&strを直接使えないため、すべての場面でtext.to_string()を実行します。これはメモリとパフォーマンスに無駄です。
長所:
短所:
関数が&str型の引数を受け取り、derefや型変換をサポートするあらゆる型(&str、&String、文字列リテラル)で呼び出すことができます。不必要なアロケーションはありません。
長所:
短所: