It’s been quite some time since I coded in a lower level language than JavaScript. Distributed systems recently piqued my interest thus I decided to pick-up a lower level compiled language. I chose Rust which I knew nothing about. Inspired by @swyx’s “learn in public” I decided to document my journey learning Rust.
Matching a string against another one is a pattern you often use in development. For example let’s say we’d want to match a string representing a status against the different possible statuses. In JavaScript it could look like this:
const status = 'start';
switch (status) {
case 'ready':
/** Do something **/
break;
case 'start':
/** Do something **/
break;
case 'stop':
/** Do something **/
break;
default:
throw new Error('Unknown status');
}
Coming to Rust as a JS engineer you’d be tempted to write:
// Let's imagine this string comes from somewhere else
// and you'd get a String and not a string literal (&str)
let status = String::from("start");
match status {
"ready" => /** Do something **/,
"start" => /** Do something **/,
"stop" => /** Do something **/,
_ => /** Do something **/,
};
The compiler however will not agree as this code triggers an error:
error[E0308]: mismatched types
--> src/main.rs:5:5
|
4 | match status {
| ------ this expression has type `String`
5 | "ready" => (),
| ^^^^^^^ expected struct `String`, found `&str`
For those wondering I just replaced the comment blocks /** Do something **/
above by the unit type ()
so the compiler would not complain.
From what the compiler tells us, we understand that we gave the match
operator a String
but the pattern branches have &str
(string literals). Rust does not know how to match these two types. We could try to rewrite it as followed:
let status = String::from("start");
match status {
String::from("ready") => /** Do something **/,
String::from("start") => /** Do something **/,
String::from("stop") => /** Do something **/,
_ => /** Do something **/,
};
Sadly this won’t cut it:
error[E0164]: expected tuple struct or tuple variant, found associated function `String::from`
--> src/main.rs:5:5
|
5 | String::from("ready") => (),
| ^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
|
= help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
Function calls are not allowed in patterns (as the compiler says).
Actually the quickest way to make that code works is to cast the status String
into a string literal. We can use status.as_str()
or &status[..]
:
let status = String::from("start");
match status.as_str() {
"ready" => /** Do something **/,
"start" => /** Do something **/,
"stop" => /** Do something **/,
_ => /** Do something **/,
};
This now compiles properly 🎉. Hope it helps.