Pattern match for type casting

Hi,

I have interesting case to implement, I am creating generic util method to work with hash map, and In case if key of hash not found, going to return some Result:Err.

It is good to have if Key attribute implement Display or Debug trait, to print more info to simplify debugging. Do you know if there anyway, to make a single method that will take an generic type argument, and do kind of Pattern matching over type?

I've tried this:

fn format_key_not_found<K>(k: &K) -> String{
    match k {
        d @ Display => format!("Key {} not found", d),
        _           => format!("Key not found")
    }
}

However unfortunately getting an error:

error[E0277]: the trait bound `K: std::fmt::Display` is not satisfied
  --> src\plugin\helpers\collections.rs:12:52
   |
12 |         d @ Display => format!("Key {} not found", d),
   |                                                    ^ `K` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
   |
   = help: the trait `std::fmt::Display` is not implemented for `K`
   = help: consider adding a `where K: std::fmt::Display` bound
   = note: required because of the requirements on the impl of `std::fmt::Display` for `&K`
   = note: required by `std::fmt::Display::fmt`

I've made additional couple test regarding it, I see that rust pattern match identified k as Display type, but d variable is still of type K, not Display.

You can't do this. If you don't specify a trait constraint on a generic type, you cannot use that trait with that type. You didn't say you wanted K: Display, so even if K implements Display, you can't use it.

impl or !impl, there is no Option.

(Specialization will change this, but it's stable yet.)

2 Likes

Not sure how you came to that conclusion; the @ pattern syntax does not do anything regarding types. In fact, all pattern matching works on values, not types.

The closest you can come to what you wanted to do is with Any.

1 Like

This functionality requires specialization. For now, I would put a Debug constraint on your keys, or you could use Any and downcasting, but that would be more complicated.

1 Like
 fn format_key_not_found<K>(k: &K) -> String{
    match k {
        d @ Display => format!("Key Display not found"),
        _           => format!("Key not found")
    }
}

Beacause prints Key Display not found, so specialization is smart enough to understand that K type is Display, but I can't use it further.

Just tried to use Any and downcast, however downcast doesn't work with Display trait.

error: the `downcast_ref` method cannot be invoked on a trait object

In Java we printing many data into a log, it help to do the debugging especially rarely reproducible cases in production. In rust expected to see something like that, however it seems that I just can't print any value into log whatever I need...

==========================
Thank you for your answers!

Have you actually tried that latest code? I don't get any output, but a compile error:

error[E0303]: pattern bindings are not allowed after an `@`
 --> src/main.rs:7:13
  |
7 |         d @ Display => format!("Key Display not found"),
  |             ^^^^^^^ not allowed after `@`

warning: unreachable pattern
 --> src/main.rs:8:9
  |
7 |         d @ Display => format!("Key Display not found"),
  |             ------- matches any value
8 |         _           => format!("Key not found")
  |         ^ unreachable pattern
  |
  = note: #[warn(unreachable_patterns)] on by default

This shows you two things:

  1. @ does not do anything with types, as I already said
  2. the Display would just be another pattern that gives a name to "anything". It has nothing to do with the trait Display. Since having something named both before and after the @ would be confusing, Rust forbids it.