Pattern matching structs with owned Strings?

Suppose I have some struct Foo like so:

struct Foo {
    bar: String,
    baz: u32,
    ... // There could be more fields, but it isn't really relevant.
}

Is there a way to construct a struct pattern that affirms Foo.bar is some known String? For example, if method calls were allowed in patterns, something like this would solve the problem:

let qux: Foo = Foo::randomized(); // irrelevant!
match qux {
    Foo { bar: "quux".to_owned(), baz, ..} => println!("qux.bar was \"quux\"!"),
    _ => panic!("qux.bar was not \"quux\"!")
}

I am aware of the following options:

  • Extract the fields to a tuple beforehand, converting to &str while doing so, and matching against the tuple.
  • Using match guards and calling methods there.

The goal here is more to understand the way patterns work with structs than to solve any specific problem. An example of a desired answer I suspect might exist is:

There is some trait or set of traits that can be implemented for Foo that allow you to match against &qux, where &qux treats qux.bar as &str rather than &String.

Currently, it is never possible to execute any other code inside of the process of matching a pattern — in particular, for your case, it is not possible to invoke String::deref(). Patterns only ever compare discriminants and values in ways built in to the compiler.

1 Like

There's a feature for it.

#![feature(string_deref_patterns)]
 
struct Foo {
    bar: String,
    baz: u32,
}

fn check(qux: Foo) {
    match qux {
        Foo { bar: "quux", baz, .. } => println!("yay"),
        _ => panic!("boo"),
    }
}

(Playground.)

I prefer a borrowed version of the struct to retain field names and so on.

2 Likes

Both of these seem like good options to me! I think creating a borrowed version of the struct is the solution I was trying to figure out, but I thought it'd be a trait.