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

D. *_*aro 5 rust

我正在阅读关于Strings 的书籍部分,并发现他们正在&*结合使用来转换一段文字.它的内容如下:

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.
Run Code Online (Sandbox Code Playgroud)

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

Luk*_*odt 10

简而言之:*触发器显式deref,可以通过重载ops::Deref.


更多详情

看看这段代码:

let s = "hi".to_string();  // : String
let a = &s;
Run Code Online (Sandbox Code Playgroud)

这是什么类型的a?这很简单&String!这不应该是非常令人惊讶的,因为我们参考了一个String.好的,但是这个呢?

let s = "hi".to_string();  // : String
let b = &*s;   // equivalent to `&(*s)`
Run Code Online (Sandbox Code Playgroud)

这是什么类型的b?是的&str!哇,发生什么事了?

请注意,*s首先执行.作为大多数运算符,解除引用运算符*也是可重载的,并且运算符的使用可以被认为是语法糖*std::ops::Deref::deref(&s)(注意我们在这里递归地解引用!).String 确实重载此运算符:

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

所以,*s实际上是*std::ops::Deref::deref(&s),在该deref()函数的返回类型&str,然后再解除引用.因此,*s有类型str(注意缺乏&).

既然str没有大小并且不是很方便,我们希望改为引用它,即&str.我们可以通过&在表达式前面添加一个来做到这一点!田田,现在我们达到了这个类型&str!


&*s而是手工和显性形式.通常,Deref-overload通过自动deref强制使用.修复目标类型后,编译器将为您解释:

fn takes_string_slice(_: &str) {}

let s = "hi".to_string();  // : String
takes_string_slice(&s); // this works!
Run Code Online (Sandbox Code Playgroud)


She*_*ter 8

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

但是,鲁斯特已经下定决心.结合DerefDerefMut特征,一种类型可以取消引用不同的类型!

本作是有用StringS作为这意味着他们可以得到所有的方法从str,它是有用的Vec<T>,因为它获得的方法[T],它是为所有的智能指针一样,超级有用Box<T>,这将对所有的方法中包含的T!

以下链接String:

String --deref--> str --ref--> &str
Run Code Online (Sandbox Code Playgroud)

&我们是不是意味着它的参考,然后使用它*来取消引用它?

不,您的操作顺序是倒退的.*&与权利相关联.在此示例中,首先解除引用,然后引用.

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

(来自评论)

有时候,这会做同样的事情.请参阅什么是Rust的确切自动解除引用规则?对于完整的细节,但是,&String可以将a传递给需要a的函数&str.有时你需要手工做这个小舞蹈.我能想到的最常见的是:

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

你会注意到我们实际上是两次取消引用:

&String -->deref--> String --deref--> str --ref--> &str
Run Code Online (Sandbox Code Playgroud)

虽然这种情况现在可以用 name.as_ref().map(String::as_str);