Appearance
16.4 有时候需要手动处理
如果智能指针中的方法与它内部成员的方法冲突了怎么办呢?编译器会优先调用当前最匹配的类型,而不会执行自动deref
,在这种情况下,我们就只能手动deref
来表达我们的需求了。
比如说,Rc 类型和 String 类型都有clone
方法,但是它们执行的任务不同。Rc::clone()
做的是把引用计数指针复制一份,把引用计数加 1。String::clone()
做的是把字符串深复制一份。示例如下:
rust
use std::rc::Rc;
use std::ops::Deref;
fn type_of(_: ()) { }
fn main() {
let s = Rc::new(Rc::new(String::from("hello")));
let s1 = s.clone(); // (1)
//type_of(s1);
let ps1 = (*s).clone(); // (2)
//type_of(ps1);
let pps1 = (**s).clone(); // (3)
//type_of(pps1);
}
在以上的代码中,位置(1)处s1
的类型为Rc<Rc<String>>
,位置(2)处ps1
的类型为Rc<String>
,位置(3)处pps1
的类型为 String。
一般情况下,在函数调用的时候,编译器会帮我们尝试自动解引用。但在某些情况下,编译器不会为我们自动插入自动解引用的代码。以 String 和&str
类型为例,在 match 表达式中:
rust
fn main() {
let s = String::new();
match &s {
"" => {}
_ => {}
}
}
这段代码编译会发生错误,错误信息为:
rust
mismatched types:
expected `&collections::string::String`,
found `&'static str`
match
后面的变量类型是&String
,匹配分支的变量类型为&'static str
,这种情况下就需要我们手动完成类型转换了。手动将&String
类型转换为&str
类型的办法如下。
1)match s.deref()
。这个方法通过主动调用deref()
方法达到类型转换的目的。此时我们需要引入Deref trait
方可通过编译,即加上代码use std::ops::Deref;
。
2)match &*s
。我们可以通过*s
运算符,也可以强制调用deref()
方法,与上面的做法一样。
3)match s.as_ref()
。这个方法调用的是标准库中的std::convert::AsRef
方法,这个 trait 存在于 prelude 中,无须手工引入即可使用。
4)match s.borrow()
。这个方法调用的是标准库中的std::borrow::Borrow
方法。要使用它,需要加上代码use std::borrow::Borrow;
。
5)match &s[..]
。这个方案也是可以的,这里利用了 String 重载的 Index 操作。