为什么String :: from(* d)在&& str上给出了* d.to_string()的不同结果?

时间:2018-03-01 22:14:48

标签: rust

我有点疑惑为什么解除引用&&str似乎不适用于第二种情况:

use std::collections::HashSet;

fn main() {
    let days = vec!["mon", "tue", "wed"];
    let mut hs: HashSet<String> = HashSet::new();

    for d in &days {
        // works
        hs.insert(String::from(*d));

        // doesn't
        hs.insert(*d.to_string());
    }
    println!("{:#?}", hs);
}

str确实实现了ToString特征,但它仍然给我错误:

error[E0308]: mismatched types
  --> src/main.rs:12:19
   |
12 |         hs.insert(*d.to_string());
   |                   ^^^^^^^^^^^^^^ expected struct `std::string::String`, found str
   |
   = note: expected type `std::string::String`
              found type `str`

我在这里弄错了什么语法?

Rust Playground Link

1 个答案:

答案 0 :(得分:4)

to_string在被解析之前被调用d,因此您将对String进行deref,从而产生str

将其更改为

hs.insert(d.to_string());

这是有效的,因为d会自动解析为str,之后会转换为String。这称为Deref coercions

  

如果您有U类型,并且它实现了Deref<Target=T>&U的值将自动强制转换为&T

     

...

     

Deref也会在调用方法时启动

这是exactly the case hereimpl Deref<Target = str> for String。见here for an example

  

类型&&&&&&&&&&&&&&&&Foo的值仍然可以在调用Foo上定义方法,因为编译器将根据需要插入尽可能多的*操作以使其正确。由于它正在插入*s,因此使用Deref

example证明了这一点:

struct Foo;

impl Foo {
    fn foo(&self) { println!("Foo"); }
}

let f = &&Foo;

// prints "foo"
f.foo();

顺便说一下,

hs.insert((*d).to_string());

也会work,因为它首先是&str