I am trying to make reimplementation of first 2 Final Fantasy games using original data from various platforms. I want to get 2 program arguments using the getopts crate and handle both of them by using match but it just executes the first match element. I think I screwed up something with types.
Maybe there is another way to do it? I am lost using the official Rust docs and any tutorials on internet are not really noob-friendly.
Here is the code:
let args: Vec<String> = env::args().map(|x| x.to_string()).collect();
if(args.len() < 3) {
println!("=====ERROR=====\nInvalid number of parameters\nExpected: <gamename> <gamerom>\nType in: 'help me' to get some help.");
process::exit(1);
}
let ref game = args[1];
let ref rom = args[2];
match game {
help => {
println!("=====HELP======");
match rom {
list => println!("Available games: ff1, ff2\nAvailable roms: ff1_j_msx, ff1_j_nes, ff1_u, ff1and2, ff2_j, ff2_u_proto"),
me => println!("Available help commands:\nlist -> List of available games and roms.\nme -> This help"),
_ => println!("=====ERROR=====\nInvalid help command.")
}
},
_ => println!("=====ERROR=====\nInvalid game, type in 'help me' to get some help.")
}
You really need to read the compilers error and warning messages. This code has seven warnings. If you had addressed any of them you'd be a lot closer to fixing the problem yourself. If you'd fixed all of them, your problem would be gone.
Here's a representative warning where the compiler tells you exactly what the problem is:
warning: unreachable pattern
--> src/main.rs:24:5
|
24 | _ => println!("=====ERROR=====\nInvalid game, type in 'help me' to get some help.")
| ^ this is an unreachable pattern
|
= note: #[warn(unreachable_patterns)] on by default
note: this pattern matches any value
--> src/main.rs:15:5
|
15 | help => {
| ^^^^
When you use just help, that creates a new variable with the value you are matching on. In this case, it matches everything, so the subsequent arms can never match.
Instead, you need to match against a string literal:
match game.as_str() {
"help" => {
match rom.as_str() {
"list" => /* ... */,
"me" => /* ... */,
_ => /* ... */,
}
},
_ => /* ... */,
}
I'd strongly encourage you to go back and re-read The Rust Programming Language. It's where a lot of the beginner documentation is kept. Specifically, you should read from the beginning and then up through the chapter on match and the chapter on patterns.
Related
This question already has answers here:
How can I pattern match against an Option<String>?
(4 answers)
Closed 8 months ago.
Problem description
I'm trying to match option string with match statement
let option_string = Some(String::from("Bob"));
match option_string {
Some("Mike") => false,
Some("Bob") => true,
_ => false,
}
And, obviously, got an error expected struct 'String, found '&str'.
I tried to change it into string cast
Some("Mike".to_string()) => false
// Or
Some(String::from("Mike")) => false
But faced with a different error: 'fn' calls are not allowed in patterns
The only working way is to place Mike into a variable before Some
let mike = String::from("Mike");
// and in match
Some(mike) => true,
Question
There is a more elegant way to match String but not string literals in match cases with Option value?
I found the answer but it doesn't look elegant enough too. But is it only one possible way to not create extra variables or functions?
let mike = String::from("Mike");
// and in match
Some(mike) => true,
This one is actually a misconception, I'm afraid. Variables are not allowed on the left side of a match expression. Having a name on the left side actually creates a new variable that contains the matched content. So the mike variable in your match clause matches everything and then carries the matched String; it is not the same variable as the outer mike variable.
Pay attention to this code example:
fn main() {
let option_string = Some(String::from("Bob"));
// Note how this line gets the compiler warning "unused variable".
// You could leave this line out completely and it would still
// compile.
let mike = String::from("Mike");
let result = match option_string {
Some(mike) => {
println!("Matched 'Mike': {}", mike);
true
}
_ => false,
};
println!("{:?}", result);
}
Matched 'Mike': Bob
true
In general, you can only match against compile time constants. If you want to compare two variables, you have to use if instead.
Solution
That said, your first example is quite easy to fix:
fn main() {
let option_string = Some(String::from("Bob"));
let result = match option_string.as_deref() {
Some("Mike") => false,
Some("Bob") => true,
_ => false,
};
println!("{:?}", result);
}
true
Note the .as_deref(), which borrows an Option<&str> from the Option<String>, making it compatible with the string literal match expressions.
Still very new to Rust, trying to understand how to extract the title of a JournalArticle using the Zotero crate.
I've got this, and can confirm the item is retrieved successfully:
let zc = ZoteroCredentials::new();
let z = ZoteroInit::set_user(&zc.api_id, &zc.api_key);
let item = z.get_item(item_id, None).unwrap();
From here, I see that an item.data is an ItemType, specifically a JournalArticleData. But I'm fundamentally not quite understanding how to either a) serialize this to JSON, or b) access .title as a property.
For context, this would be the result of a Rocket GET route.
Any help would much appreciated!
It sounds like the part you're missing is how to use pattern matching on an enum. I'm not familiar with zotero so this is all based on the docs, with verbose type annotations to be explicit about what I think I'm doing:
use zotero::data_structure::item::{Item, ItemType, JournalArticleData};
let item: Item = z.get_item(item_id, None).unwrap();
// Now we must extract the JournalArticle from the ItemType, which is an enum
// and therefore requires pattern matching.
let article: JournalArticleData = match item.data {
ItemType::JournalArticle(a) => a,
something_else => todo!("handle wrong type of item"),
}
let title: String = article.title;
(The match could also be written as an if let just as well.)
You could also use pattern matching to go through the entire structure, rather than only the enum which requires it:
match z.get_item(item_id, None).unwrap() {
Item {
data: ItemType::JournalArticle(JournalArticleData {
title,
..
}),
..
} => {
// Use the `title` variable here
},
something_else => todo!("handle wrong type of item"),
}
I wrote the following code :
macro_rules! my_macro{
("A") => {
println!("Macro called !")
}
}
fn main(){
static test: &'static str = "A";
my_macro!(test);
}
but I have the following error :
error: no rules expected the token `test`
--> test.rt:9:19
|
1 | macro_rules! my_macro{
| --------------------- when calling this macro
...
9 | my_macro!(test);
| ^^^^ no rules expected this token in macro call
error: aborting due to previous error
However, it works fine if I directly call my_macro("A"). Is it possible to fix this ?
Is it possible to fix this ?
No. Macros are expanded at compile time before item names are resolved, therefore your macro has no idea what the value of test is (and would have no idea even if it were a const rather than a static).
so the first problem here is that you macro expects a pattern of "A" not a variable that contains "A"
when you create macros you define certain patterns and follow those patterns in your case your macro must always have "A" in it but it is not a string a it is a pattern of double quote followed by capital a followed by another double quote
If you want to pass a value you should use variable syntax and define what it should expect such as ($a:expr)=>{...}
here you can see all magic tokens possible just scroll down a bit on that docs there are a lot of great examples
PS. here is a macro I use for responding from my endpoints
macro_rules! resp {
(ok) => {
|_| actix_web::HttpResponse::Ok().body(r#"{"success":true}"#)
};
(ok,$data:expr) => {
|_| actix_web::HttpResponse::Ok().json(serde_json::json!({"success":true,"data":$data}))
};
(ok,) => {
|d| actix_web::HttpResponse::Ok().json(serde_json::json!({"success":true,"data":d}))
};
}
Consider the following code sample (playground).
#[derive(PartialEq, Clone, Debug)]
enum State {
Initial,
One,
Two,
}
enum Event {
ButtonOne,
ButtonTwo,
}
struct StateMachine {
state: State,
}
impl StateMachine {
fn new() -> StateMachine {
StateMachine {
state: State::Initial,
}
}
fn advance_for_event(&mut self, event: Event) {
// grab a local copy of the current state
let start_state = self.state.clone();
// determine the next state required
let end_state = match (start_state, event) {
// starting with initial
(State::Initial, Event::ButtonOne) => State::One,
(State::Initial, Event::ButtonTwo) => State::Two,
// starting with one
(State::One, Event::ButtonOne) => State::Initial,
(State::One, Event::ButtonTwo) => State::Two,
// starting with two
(State::Two, Event::ButtonOne) => State::One,
(State::Two, Event::ButtonTwo) => State::Initial,
};
self.transition(end_state);
}
fn transition(&mut self, end_state: State) {
// update the state machine
let start_state = self.state.clone();
self.state = end_state.clone();
// handle actions on entry (or exit) of states
match (start_state, end_state) {
// transitions out of initial state
(State::Initial, State::One) => {}
(State::Initial, State::Two) => {}
// transitions out of one state
(State::One, State::Initial) => {}
(State::One, State::Two) => {}
// transitions out of two state
(State::Two, State::Initial) => {}
(State::Two, State::One) => {}
// identity states (no transition)
(ref x, ref y) if x == y => {}
// ^^^ above branch doesn't match, so this is required
// _ => {},
}
}
}
fn main() {
let mut sm = StateMachine::new();
sm.advance_for_event(Event::ButtonOne);
assert_eq!(sm.state, State::One);
sm.advance_for_event(Event::ButtonOne);
assert_eq!(sm.state, State::Initial);
sm.advance_for_event(Event::ButtonTwo);
assert_eq!(sm.state, State::Two);
sm.advance_for_event(Event::ButtonTwo);
assert_eq!(sm.state, State::Initial);
}
In the StateMachine::transition method, the code as presented does not compile:
error[E0004]: non-exhaustive patterns: `(Initial, Initial)` not covered
--> src/main.rs:52:15
|
52 | match (start_state, end_state) {
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(Initial, Initial)` not covered
But that is exactly the pattern I'm trying to match! Along with the (One, One) edge and (Two, Two) edge. Importantly I specifically want this case because I want to leverage the compiler to ensure that every possible state transition is handled (esp. when new states are added later) and I know that identity transitions will always be a no-op.
I can resolve the compiler error by uncommenting the line below that one (_ => {}) but then I lose the advantage of having the compiler check for valid transitions because this will match on any states added in the future.
I could also resolve this by manually typing each identity transition such as:
(State::Initial, State::Initial) => {}
That is tedious, and at that point I'm just fighting the compiler. This could probably be turned into a macro, so I could possibly do something like:
identity_is_no_op!(State);
Or worst case:
identity_is_no_op!(State::Initial, State::One, State::Two);
The macro can automatically write this boilerplate any time a new state is added, but that feels like unnecessary work when the pattern I have written should be covering the exact case that I'm looking for.
Why doesn't this work as written?
What is the cleanest way to do what I am trying to do?
I have decided that a macro of the second form (i.e. identity_is_no_op!(State::Initial, State::One, State::Two);) is actually the preferred solution.
It's easy to imagine a future in which I do want some of the states to do something in the 'no transition' case. Using this macro would still have the desired effect of forcing the state machine to be revisited when new States are added and would just require adding the new state to the macro arglist if nothing needs to be done. A reasonable compromise IMO.
I think the question is still useful because the behavior was surprising to me as a relatively new Rustacean.
Why doesn't this work as written?
Because the Rust compiler cannot take guard expressions into account when determining if a match is exhaustive. As soon as you have a guard, it assumes that guard could fail.
Note that this has nothing to do with the distinction between refutable and irrefutable patterns. if guards are not part of the pattern, they're part of the match syntax.
What is the cleanest way to do what I am trying to do?
List every possible combination. A macro could slightly shorten writing the patterns, but you can't use macros to replace entire match arms.
I am very new to rust and trying to write a command line utility as a way to learn.
I am getting the list of args and trying to match on them
let args = os::args()
//some more code
match args[1].into_ascii_lower().as_slice() {
"?" | "help" => { //show help },
"add" => { //do other stuff },
_ => { //do default stuff }
}
this causes this error
cannot move out of dereference (dereference is implicit, due to indexing)
match args[1].into_ascii_lower().as_slice() {
^~~~~~~
I have no idea what that means, but searching yield this which I didn't completely get, but changing the args[1] to args.get(1) gives me another error
error: cannot move out of dereference of `&`-pointer
match args.get(1).into_ascii_lower().as_slice() {
^~~~~~~~~~~
what's going on?
As you can see in the documentation, the type of into_ascii_lower() is (see here) :
fn into_ascii_upper(self) -> Self;
It takes self directly, not as a reference. Meaning it actually consumes the String and return an other one.
So, when you do args[1].into_ascii_lower(), you try to directly consume one of the elements of args, which is forbidden. You probably want to make a copy of this string, and call into_ascii_lower() on this copy, like this :
match args[1].clone().into_ascii_lower().as_slice() {
/* ... */
}