11

String implements Deref<Target = str>, which means that the following code compiles:

fn save(who: &str) {
    println!("I'll save you, {}!", who);
}

save(&String::from("Madoka"));

If I create a custom type that also implements Deref<Target = str>, then that works too:

struct Madoka;

impl Deref for Madoka {
    type Target = str;
    fn deref(&self) -> &Self::Target {
        "Madoka"
    }
}

save(&Madoka);

Now, let's try coercing to another type -- say, u32. It seems to work as well:

fn reset(how: &u32) {
    println!("Reset {} times", how);
}

struct Homura;

impl Deref for Homura {
    type Target = u32;
    fn deref(&self) -> &Self::Target {
        &42
    }
}

reset(&Homura);

But when I wrap the expression in a block, it no longer compiles:

reset(&{ Homura });
error[E0308]: mismatched types
  --> src/main.rs:17:14
   |
17 |     reset(&{ Homura });
   |              ^^^^^^ expected u32, found struct `main::Homura`
   |
   = note: expected type `u32`
              found type `main::Homura`

The weird thing is that the equivalent expression with &str compiles just fine:

save(&{ Madoka });  // OK

Why does the first expression fail to compile, but the second succeed?

Playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lambda Fairy
  • 13,814
  • 7
  • 42
  • 68
  • 1
    I'm not sure why this is, but you can make it work by using two ampersands: `reset(&&{Homura});` or putting the ampersand inside the block: `reset({&Homura});` – Peter Hall Dec 24 '18 at 01:32
  • 4
    Usually in these situations I will say that it's a bug, and then @trentcl will explain how it's actually expected behaviour. With that in mind... I think it looks like a bug. – Peter Hall Dec 24 '18 at 01:36
  • 1
    There seems to be something special about slices. If `&Deref::Target` is a slice then it works. – Peter Hall Dec 24 '18 at 01:53
  • 2
    @PeterHall Sorry to disappoint, because I think this must be a bug. ;-) – trent Dec 24 '18 at 13:38
  • It also works like these : `let h = &{Homura}; reset(h);` or `reset(&*{Homura});` – Ömer Erden Dec 24 '18 at 18:41
  • 1
    I've filed an issue on [GitHub](https://github.com/rust-lang/rust/issues/57749). – Lambda Fairy Jan 19 '19 at 02:02

0 Answers0