In short:*
触发一个显式的deref,可以通过ops::Deref
重载.
更多细节
看看下面的代码:
let s = "hi".to_string(); // : String
let a = &s;
a
是什么类型的?简直是&String
!这并不奇怪,因为我们参考了String
.好吧,但是这个呢?
let s = "hi".to_string(); // : String
let b = &*s; // equivalent to `&(*s)`
b
是什么类型的?是&str
!哇,发生什么事了?
注意,首先执行*s
.与大多数操作符一样,解引用操作符*
也是可重载的,并且可以将操作符的使用视为*std::ops::Deref::deref(&s)
的语法糖(注意,我们在这里递归地解引用!).String
does过载此操作员:
impl Deref for String {
type Target = str;
fn deref(&self) -> &str { ... }
}
因此,*s
实际上是*std::ops::Deref::deref(&s)
,其中deref()
函数具有返回类型&str
,然后再次取消引用.因此,*s
具有str
型(注意缺少&
).
因为str
本身没有大小,也不是很方便,所以我们想用&str
来代替它.我们可以通过在表达式前面添加&
来实现这一点!塔达,现在我们到了&str
型!
&*s
更像是手动和明确的形式.通常,Deref
重载是通过自动解除强制来使用的.当目标类型固定后,编译器将为您解除:
fn takes_string_slice(_: &str) {}
let s = "hi".to_string(); // : String
takes_string_slice(&s); // this works!