什么& *结合在一起做Rust?

时间:2016-12-21 22:33:27

标签: rust

我正在阅读有关String的书籍部分,并发现他们正在使用&*组合在一起来转换一段文字。以下是它的说法:

use std::net::TcpStream;

TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str.

let addr_string = "192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // Convert `addr_string` to &str.

换句话说,他们说他们正在将String转换为&str。但为什么使用上述两种标志进行转换呢?如果不使用其他方法吗? &是否意味着我们正在引用它,然后使用*取消引用它?

2 个答案:

答案 0 :(得分:10)

简而言之*触发显式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 重载此运算符:

impl Deref for String {
    type Target = str;
    fn deref(&self) -> &str { ... }
}

因此,*s实际上是*std::ops::Deref::deref(&s),其中deref()函数的返回类型为&str,然后再次取消引用。因此,*s的类型为str(请注意缺少&)。

由于str未经过简化而且不是非常方便,我们希望改为引用它,即&str。我们可以通过在表达式前添加&来实现此目的! Tada,现在我们达到了类型&str

&*s更像是手动和明确的形式。通常,Deref - 过载通过自动deref强制来使用。修复目标类型后,编译器将为您解析:

fn takes_string_slice(_: &str) {}

let s = "hi".to_string();  // : String
takes_string_slice(&s); // this works!

答案 1 :(得分:8)

通常,&*表示首先取消引用(*),然后引用(&)一个值。在许多情况下,这将是愚蠢的,因为我们最终会做同样的事情。

然而,Rust有deref coercions。结合DerefDerefMut特征,类型可以取消引用不同的类型!

这对于String很有用,因为这意味着他们可以从str获取所有方法,它对Vec<T>有用,因为它从[T]获取方法,它对所有智能指针都非常有用,比如Box<T>,它将包含包含T的所有方法

关注String的链:

String --deref--> str --ref--> &str
  

&是否意味着我们正在引用它,然后使用*取消引用它?

不,您的操作顺序是倒退的。 *&与右侧相关联。在此示例中,首先取消引用,然后引用。

  

我想现在你可以做到这一点&addr_string

(来自评论)

有时候,这会做同样的事情。有关详细信息,请参阅What are Rust's exact auto-dereferencing rules?,但是,可以将&String传递给需要&str的函数。有时你需要手工做这个小舞蹈。我能想到的最常见的是:

let name: Option<String> = Some("Hello".to_string());
let name2: Option<&str> = name.as_ref().map(|s| &**s);

您会注意到我们实际取消引用两次

&String -->deref--> String --deref--> str --ref--> &str

虽然现在可以使用name.as_ref().map(String::as_str);

完成此案例