I'm trying to match on the datatype of a generic field of a struct and react accordingly. My general idea was like this (code doesn't compile):
struct Foo<T> {
bar: T,
}
fn main() {
let x = Foo::<String> {
bar: "world".to_string(),
};
match x.bar {
String => println!("It's a string!"),
u32 => println!("It's a u32!"),
_ => println!("Something else"),
};
println!("end of program!");
}
The error message from the compiler:
warning: unreachable pattern
--> src/main.rs:12:9
|
11 | String => println!("It's a string!"),
| ------ matches any value
12 | u32 => println!("It's a u32!"),
| ^^^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: unreachable pattern
--> src/main.rs:13:9
|
11 | String => println!("It's a string!"),
| ------ matches any value
12 | u32 => println!("It's a u32!"),
13 | _ => println!("Something else"),
| ^ unreachable pattern
warning: unused variable: `String`
--> src/main.rs:11:9
|
11 | String => println!("It's a string!"),
| ^^^^^^ help: consider prefixing with an underscore: `_String`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `u32`
--> src/main.rs:12:9
|
12 | u32 => println!("It's a u32!"),
| ^^^ help: consider prefixing with an underscore: `_u32`
warning: variable `String` should have a snake case name
--> src/main.rs:11:9
|
11 | String => println!("It's a string!"),
| ^^^^^^ help: convert the identifier to snake case: `string`
|
= note: `#[warn(non_snake_case)]` on by default
What I wanted was for x
to match the first one. I'm actually not sure what I want to do can be done, but what would achieve the desired effect?
Idiomatic Solution
Create a trait which constrains the parameter T
in Foo
, implement any specific behavior as an associated function of this trait.
Example:
trait PrintMe {
fn print_me(&self);
}
impl PrintMe for String {
fn print_me(&self) { println!("I am a string"); }
}
struct Foo<T: PrintMe> {
bar: T
}
fn main() {
// ...
x.bar.print_me();
}
This is principled generic programming, where you declare exactly the difference of behavior of the possible generic parameters, so that there is no surprise.
See also:
Exact Solution
Rust can indeed query types: each type has a unique TypeId
associated, and you can match on TypeId
with a series of if
checks. It's clunky.
fn print_me<T>(x: &Foo<T>) {
if TypeId::of::<T>() == TypeId::of::<String>() {
println!("I am a string");
} else // ...
}
But please... don't do that :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With