注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
Borrow
トレイトと AsRef
トレイトはとてもよく似ていますが違うものです。ここでは2つのトレイトの意味を簡単に説明します。
Borrow
トレイトはデータ構造を書いていて、所有型と借用型を同等に扱いたいときに使います。
例えば、 HashMap
には Borrow
を使った get
メソッド があります。
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
このシグネチャは少し複雑です。K
パラメータに注目してください。これは以下のように HashMap
自身のパラメータになっています。
struct HashMap<K, V, S = RandomState> {
K
パラメータは HashMap
の「キー」を表す型です。ここで再び get()
のシグネチャを見ると、キーが Borrow<Q>
を実装しているときに get()
を使えることが分かります。そのため、以下のように String
をキーとした HashMap
を検索するときに &str
を使うことができます。
use std::collections::HashMap; let mut map = HashMap::new(); map.insert("Foo".to_string(), 42); assert_eq!(map.get("Foo"), Some(&42));
これは標準ライブラリが impl Borrow<str> for String
を提供しているためです。
所有型か借用型のどちらかを取りたい場合、たいていは &T
で十分ですが、借用された値が複数種類ある場合 Borrow
が役に立ちます。特に参照とスライスは &T
と &mut T
のいずれも取りうるため、そのどちらも受け入れたい場合は Borrow
がよいでしょう。
use std::borrow::Borrow; use std::fmt::Display; fn foo<T: Borrow<i32> + Display>(a: T) { println!("a is borrowed: {}", a); } let mut i = 5; foo(&i); foo(&mut i);
上のコードは a is borrowed: 5
を二度出力します。
AsRef
トレイトは変換用のトレイトです。ジェネリックなコードにおいて、値を参照に変換したい場合に使います。
let s = "Hello".to_string(); fn foo<T: AsRef<str>>(s: T) { let slice = s.as_ref(); }
ここまでで見てきた通り、2つのトレイトは、どちらもある型の所有型バージョンと借用型バージョンの両方を扱う、という意味で同じような種類のものですが、少し違います。
いくつかの異なる種類の借用を抽象化したい場合や、ハッシュ化や比較のために所有型と借用型を同等に扱いたいデータ構造を作る場合は Borrow
を使ってください。
ジェネリックなコードで値を参照に直接変換したい場合は AsRef
を使ってください。