수색…


도트 연산자

. 녹에서 운영자는 많은 마술이 함께합니다! 당신이 사용할 때 . , 컴파일러는 메서드를 deref "tree"아래에 찾는 데 필요한 많은 * s (참조 해제 작업)를 삽입합니다. 컴파일 할 때 발생하기 때문에 메서드를 찾는 데 런타임 비용이 없습니다.

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();

여기서 iterVec<T> 의 방법이 아니라 [T] 의 방법입니다. 그것은 Vec<T>Target=[T] 를 가진 Deref구현 하기 때문에 작동합니다. * 연산자 (컴파일러가 a에서 삽입 할 수 있습니다 . )에 의해 역 참조 될 때 Vec<T>[T] 로 바뀝니다.

데 레프 강제 변환

을 감안할 때 두 종류의 TU , &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 를 취합니다.

work_on_bytes(vec);
work_on_bytes(arr);
work_on_bytes(slice);
work_on_bytes("strings work too!");

Option 및 래퍼 구조에 대한 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를 얻기 위해 필요한만큼 반복합니다. 예를 들면 다음과 같습니다.

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