トレイト AsRef

Since 1.0.0 (const: unstable) · Source

pub trait AsRef<T>where
	T: ?Sized,
{
    // Required method
    fn as_ref(&self) -> &T;
}
説明を展開

参照から参照への安価な変換に使用される。

このトレイトは可変参照との変換に使われる AsMut と似ている。もしも高コストな変換を行う必要があるのなら &TFrom を実装するか自作の関数を書こう。

Borrow との関係

AsRefBorrow と同じシグネチャを持つが、Borrow とは幾つかの点で異なる。

  • AsRef とは違い、Borrow は任意の T に対するブランケット実装を持つため、参照と値の双方を受けいれるのに使える (下記の AsRef の反射性の但し書きを見よ)。
  • また Borrow は借用される値の Hash, Eq そして Ord が所有される値のそれと同じになる事を要求する。この理由のため、構造体の単一のフィールドのみを借用したいのなら、AsRef での実装はできるが Borrow ではできない。

Note: このトレイトは失敗してはならない。もし変換が失敗しうるなら、 Option<T>Result<T, E> を戻す専用のメソッドを使え。

一般的な実装

AsRef はもし内部の型が参照や可変参照なら自動逆参照する (例: foo.as_ref()foo&mut Foo&&mut Foo なら同じ働きをする)。

なお歴史的経緯のため現在、上記は全ての逆参照可能型で一般化されているわけではなく、例えば foo.as_ref()Box::new(foo).as_ref() と同じ働きとはならない。代わりに、多くのスマートポインタは単純にポイントされた値への参照を戻すだけの as_ref の実装を提供する (逆にその値には参照から参照への低コストな変換は実施されない)。とは言え、AsRef::as_ref を逆参照だけの目的で使うべきではない; 代わりに Deref 強制’ が使用できる:

let x = Box::new(5i32);
// これは避けて:
// let y: &i32 = x.as_ref();
// こう書くだけで良い:
let y: &i32 = &x;

Deref を実装する型は AsRef<T> を以下のように実装するよう考慮すべきである:

impl<T> AsRef<T> for SomeType
where
    T: ?Sized,
    <SomeType as Deref>::Target: AsRef<T>,
{
    fn as_ref(&self) -> &T {
        self.deref().as_ref()
    }
}

反射性

理想的には、AsRef は反射的であるべきで、つまり impl<T: ?Sized> AsRef<T> for Tas_ref で単純にその引数を変更せずに戻すべきである。だが Rust の型システムの技術的制約のためそのようなブランケット実装は現在は提供されていない (それが既存のブランケット実装の &T where T: AsRef<U> と重複するためで、これは上記の『一般的な実装』の通り、AsRef に自動逆参照を可能にしている)。

特定の型 T のための AsRef<T> for T の素朴な実装が必要または期待されるなら明示的な追加が必要になる。しかしながら、std 由来の全ての型にそうした実装が含まれているわけではなく、またそれらは孤児ルールにより外部コードから追加できない事に注意せよ。

トレイト境界を使用する事で異なる型の引数をそれらが特定の型 T に変換できる限り受け入れられる。

例えば: AsRef<str> をとるジェネリック関数を作成する事で、&str に変換できる全ての参照を受け入れたい事を表現できる。String&str は共に AsRef<str> を実装しているので共に入力引数として受け入れできる。

fn is_hello<T: AsRef<str>>(s: T) {
   assert_eq!("hello", s.as_ref());
}

let s = "hello";
is_hello(s);

let s = "hello".to_string();
is_hello(s);

要求されるメソッド

1.0.0 · Source fn as_ref(&self) -> &T

この型を入力型 (通常は推論される) の共有参照へと変換する。