サーチ…
ドット演算子
.
錆のオペレータには多くの魔法が付属しています!あなたが使うとき.
コンパイラは、メソッドをderef "ツリー"の下に見つけるために必要な数( *
参照解除操作)を挿入します。これはコンパイル時に発生するため、メソッドを見つけるためのランタイム・コストはありません。
let mut name: String = "hello world".to_string();
// no deref happens here because push is defined in String itself
name.push('!');
let name_ref: &String = &name;
// Auto deref happens here to get to the String. See below
let name_len = name_ref.len();
// You can think of this as syntactic sugar for the following line:
let name_len2 = (*name_ref).len();
// Because of how the deref rules work,
// you can have an arbitrary number of references.
// The . operator is clever enough to know what to do.
let name_len3 = (&&&&&&&&&&&&name).len();
assert_eq!(name_len3, name_len);
自動逆参照は、 std::ops::Deref
特性を実装するすべての型に対しても機能します。
let vec = vec![1, 2, 3];
let iterator = vec.iter();
ここで、 iter
はVec<T>
方法ではなく、 [T]
方法です。ので、それが動作Vec<T>
実装Deref
とTarget=[T]
できVec<T>
に変わり[T]
により参照解除するとき*
演算子(コンパイラが中に挿入してもよいです.
)。
デレフ強制
与えられた2種類のT
およびU
、 &T
(暗黙的に変換)強制変換されますに&U
場合に限り、 T
実装Deref<Target=U>
これにより、次のようなことができます。
fn foo(a: &[i32]) {
// code
}
fn bar(s: &str) {
// code
}
let v = vec![1, 2, 3];
foo(&v); // &Vec<i32> coerces into &[i32] because Vec<T> impls Deref<Target=[T]>
let s = "Hello world".to_string();
let rc = Rc::new(s);
// This works because Rc<T> impls Deref<Target=T> ∴ &Rc<String> coerces into
// &String which coerces into &str. This happens as much as needed at compile time.
bar(&rc);
関数の引数にDerefとAsRefを使う
オブジェクトのコレクションを取る必要がある関数の場合、スライスは通常は良い選択です。
fn work_on_bytes(slice: &[u8]) {}
Vec<T>
と配列[T; N]
はDeref<Target=[T]>
実装するので、簡単にスライスに強制することができます。
let vec = Vec::new();
work_on_bytes(&vec);
let arr = [0; 10];
work_on_bytes(&arr);
let slice = &[1,2,3];
work_on_bytes(slice); // Note lack of &, since it doesn't need coercing
しかし、明示的にスライスを要求するのではなく、スライスとして使用できる任意の型を受け入れるように関数を作成することができます。
fn work_on_bytes<T: AsRef<[u8]>>(input: T) {
let slice = input.as_ref();
}
この例では、関数work_on_bytes
は、 [u8]
への参照を返すas_ref()
を実装する任意の型T
を[u8]
。
work_on_bytes(vec);
work_on_bytes(arr);
work_on_bytes(slice);
work_on_bytes("strings work too!");
オプションとラッパー構造体のDeref実装
use std::ops::Deref;
use std::fmt::Debug;
#[derive(Debug)]
struct RichOption<T>(Option<T>); // wrapper struct
impl<T> Deref for RichOption<T> {
type Target = Option<T>; // Our wrapper struct will coerce into Option
fn deref(&self) -> &Option<T> {
&self.0 // We just extract the inner element
}
}
impl<T: Debug> RichOption<T> {
fn print_inner(&self) {
println!("{:?}", self.0)
}
}
fn main() {
let x = RichOption(Some(1));
println!("{:?}",x.map(|x| x + 1)); // Now we can use Option's methods...
fn_that_takes_option(&x); // pass it to functions that take Option...
x.print_inner() // and use it's own methods to extend Option
}
fn fn_that_takes_option<T : std::fmt::Debug>(x: &Option<T>) {
println!("{:?}", x)
}
シンプルなDerefの例
Deref
は単純なルールを持っています。タイプT
を持ち、 Deref<Target=F>
実装し、 &T
が&F
強制する&F
、コンパイラはFを得るのに必要な回数だけこれを繰り返します。
fn f(x: &str) -> &str { x }
fn main() {
// Compiler will coerce &&&&&&&str to &str and then pass it to our function
f(&&&&&&&"It's a string");
}
Deref強制は、 Box
やArc
などのポインタ型で作業する場合に特に便利です。
fn main() {
let val = Box::new(vec![1,2,3]);
// Now, thanks to Deref, we still
// can use our vector method as if there wasn't any Box
val.iter().fold(0, |acc, &x| acc + x ); // 6
// We pass our Box to the function that takes Vec,
// Box<Vec> coerces to Vec
f(&val)
}
fn f(x: &Vec<i32>) {
println!("{:?}", x) // [1,2,3]
}
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow