rust-course/codes/src/deep-trait/deref.md

61 lines
1.7 KiB

# Deref
下面的代码会报错
```rust
use std::ops::Index;
use std::rc::Rc;
struct MyType<T> { bytes: T }
// Wow such clean much wow
impl<T: Index<I>, I> Index<I> for MyType<T> {
type Output = T::Output;
fn index(&self, index: I) -> &Self::Output {
&self.bytes[index]
}
}
fn main() {
let rc1 = Rc::new([1, 2, 3]);
rc1[0]; // OK
let rc2 = MyType { bytes: Rc::new([1, 2, 3]) };
rc2[0]; // error[E0608]: cannot index into a value of type `MyType<Rc<[{integer}; 3]>>`
// WHY???!?!!?!?!?!?
}
```
报错的原因是`Rc`自身没有实现`Index<usize>`,因此需要先通过`Deref`转为内部的数据类型,再进行索引。
首先`let rc1 = Rc::new([1, 2, 3]);`能行,是因为`Rc`能通过`Deref`转为`&[]`类型,因此`Deref`后,等同于直接对内部的数组切片取索引.
而` let rc2 = MyType { bytes: Rc::new([1, 2, 3]) };`不行,是因为`Rc::new([1,2,3])`实际上是泛型类型`T`编译器并不知道T有没有实现`Deref`,因此也不能对`Rc::new([1,2,3])`进行索引。
简而言之,只有作为表达式才能自动进行`Deref`(`rc1`),作为泛型类型时,不能自动进行`Deref`(`rc2`)。
你也可以为自己的类型实现`Deref`:
```rust
use std::ops::Deref;
use std::rc::Rc;
struct MyType<T> { bytes: T }
impl<T> Deref for MyType<T> {
type Target = T;
fn deref(&self) -> &T {
&self.bytes
}
}
fn main() {
let rc = Rc::new([1, 2, 3]);
rc[0]; // OK
let rc = MyType { bytes: Rc::new([1, 2, 3]) };
rc[0];
}
```
但是这不符合官方推荐的使用方式,因为官方明确推荐`Deref`适用于智能指针,其它类型要小心使用。