注意: 最新版のドキュメントをご覧ください。この第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 を使ってください。