I am toying around with Rust, and am trying to take in some input, and then splitting it by white space in to a vector of strings.
I then want to destructure these inputs again in to separate values. What I have so far is this:
use std::io;
fn main() {
println!("___Calculator___");
let mut buffer = String::new();
println!("What would you like to calculate?");
io::stdin()
.read_line(&mut buffer)
.unwrap();
let elements = buffer
.split_whitespace()
.collect::<Vec<&str>>();
let [first, second, third] = elements[0..2];
}
Again, I know I could just read input 3 times, but I want to see how I can do different things with the language.
Edit
Here's the error from cargo run:
Compiling calculator v0.1.0 (E:\code\rust\calculator)
error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
--> src\main.rs:18:9
|
18 | let [first, second, third] = elements[0..2];
| ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `[&str]`
help: you might want to use `if let` to ignore the variants that aren't matched
|
18 | let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
| +++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `calculator` due to previous error
Thanks
Rust doesn't understand that elements[0..2] is always going to be three elements. In fact, it potentially won't be, if the user enters fewer than three words. So you need to handle that case.
if let [first, second, third] = &elements[0..2] {
...
} else {
println!("Enter three words plz :(");
}
EDIT: From a comment on the question, you also want elements[0..3]. Ranges are half-open in Rust.
The compiler is telling you what the problem is, and even suggests a fix:
error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
--> src/main.rs:18:9
|
18 | let [first, second, third] = elements[0..2];
| ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `[&str]`
help: you might want to use `if let` to ignore the variants that aren't matched
|
18 | let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
| +++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++
Patterns in variable declarations are required to be irrefutable, i.e. always succeed. What if the vector has less than three elements? You have to use match or if let to cover that possibility.
Related
I'm using the rusqlite crate and am doing some queries, basically i'm just trying to check the length of the query results before trying to proceed, however I'm running into error[E0382]: use of moved value: key_rows whilst trying to compile, I don't understand since i'm borrowing a reference to the variable so it wouldn't move it's local in memory?
Maybe it's due to the method i'm calling on the variable's pointer?
Full compiler error:
error[E0382]: use of moved value: `key_rows`
--> src/handle.rs:126:16
|
108 | let key_rows = key_stmt.query_map(&[(":key", key.as_str())], |row| {
| -------- move occurs because `key_rows` has type `MappedRows<'_, [closure#src/handle.rs:108:66: 113:6]>`, which does not implement the `Copy` trait
...
117 | if(&key_rows.count() == &0){
| ------- `key_rows` moved due to this method call
...
126 | for row in key_rows {
| ^^^^^^^^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `key_rows`
Erroneous code:
let mut key_stmt = conn.prepare("SELECT id , key FROM key_table WHERE key = :key;").unwrap();
let key_rows = key_stmt.query_map(&[(":key", key.as_str())], |row| {
Ok(Table {
id: row.get(0)?,
payload: row.get(1)?,
})
}).unwrap();
//Checking that the key exists:
if(&key_rows.count() == &0){
panic!("Can't find the key...")
}
//Putting in a default value since the compiler is worried.
let mut reference_id : i32 = 0;
//For loop is nessessary since MappedRow type cannot be indexed regularly (weird)
for row in key_rows {
reference_id = row.unwrap().id;
println!("{:?}", reference_id.to_string());
}
You aren't borrowing key_rows then checking the count, but rather calling key_rows.count(), then borrowing the result.
Iterator#count consumes the entire iterator, returning how many elements were traversed.
let mut reference_id = key_rows.next().unwrap_or_else(|| panic!("Can't find the key..."));
// Remove the code past this point if you are only expecting one, or the first value.
for row in key_rows {
reference_id = row.unwrap().id;
println!("{:?}", reference_id.to_string());
}
I just started programming functionally. My current tiny project to start would be a basic pokemon battle.
Code first, explanation follows.
let choosePokemon () =
let mutable pokemon = DemoData.schiggy
let msg = Console.ReadLine()
match msg with
| "Schiggy" -> pokemon <- DemoData.schiggy
| "Pikachu" -> pokemon <- DemoData.pikachu
| "Kleinstein" -> pokemon <- DemoData.kleinstein
| "Karpador" -> pokemon <- DemoData.karpador
pokemon
I am currently asking people to enter the name of a Pokemon and if it matches a predefined set (Schiggy, Pikachu, Kleinstein or Karpador) it gives them the respective Pokemon. Alternatively it gives them the default Pokemon.
I am currently creating it before matching it with "let mutable pokemon = DemoData.schiggy". I don't want that. I just want to assign it based on its name.
If I could go without that line I'd avoid making it mutable, which is something I don't want anyways.
Additional question further down the line: When Pokemon attack each other their hp will decrease.
How can I avoid using a mutable int when facing a changing int value?
Thanks in advance :)
Just return the result from the match - there's no need to declare a variable:
let choosePokemon () =
let msg = Console.ReadLine()
match msg with
| "Schiggy" -> DemoData.schiggy
| "Pikachu" -> DemoData.pikachu
| "Kleinstein" -> DemoData.kleinstein
| "Karpador" -> DemoData.karpador
The function is still impure, though, since it performs I/O (Console.ReadLine)...
It's also partial, since it'll crash on any other input than the four strings being matched. Even misspellings and case mistakes are going to throw an exception.
A more robust pure function would be something like this:
let choosePokemon (input : string) =
match input.Trim().ToUpperInvariant () with
| "PIKACHU" -> DemoData.pikachu
| "KLEINSTEIN" -> DemoData.kleinstein
| "KARPADOR" -> DemoData.karpador
| _ -> DemoData.schiggy
Contrary to the OP that performs I/O, this version is a pure function, since there's no non-deterministic behaviour. It's also total, since it returns schiggy as a default value.
To get the behaviour where you ask the user to input a value, compose the impure Console.ReadLine action with the pure choosePokemon function:
Console.ReadLine >> choosePokemon
How to push an item (struct type) from vector1 to vector2 in Rust? Can someone help me?
let mut vec1: Vec<Struct1> = vec![];
let item1 = Struct1 {
id: 1,
name: "AlgoQ".to_string()
};
vec1.push(item1);
let mut vec2: Vec<Struct1> = vec![];
vec2.push(&vec1[0]);
vec1.pop();
Error:
error[E0308]: mismatched types
--> src/test4.rs:17:15
|
17 | vec2.push(&vec1[0]);
| ^^^^^^^^
| |
| expected struct `Struct1`, found `&Struct1`
| help: consider removing the borrow: `vec1[0]`
Your item can't be at both place. You have to either
remove the item from the source vector:
vec2.push(vec1.remove(0));
Here, as you also want to pop from the first vector, you may directly do
if let Some(item) = vec1.pop() {
vec2.push(item);
}
But be careful that pop removes at the end, not at index 0 so your snippet is a little obscure regarding your exact intent.
or clone the item (assuming it can be cloned)
vec2.push(vec1[0].clone());
Now, if you really want the item to be, conceptually, at two places, you may store references (ie &Struct1) or indexes in your second vec.
I'm trying to accomplish an exercise "left to the reader" in the 2018 Rust book. The example they have, 10-15, uses the Copy trait. However, they recommend implementing the same without Copy and I've been really struggling with it.
Without Copy, I cannot use largest = list[0]. The compiler recommends using a reference instead. I do so, making largest into a &T. The compiler then complains that the largest used in the comparison is a &T, not T, so I change it to *largest to dereference the pointer. This goes fine, but then stumbles on largest = item, with complaints about T instead of &T. I switch to largest = &item. Then I get an error I cannot deal with:
error[E0597]: `item` does not live long enough
--> src/main.rs:6:24
|
6 | largest = &item;
| ^^^^ borrowed value does not live long enough
7 | }
8 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 1:1...
I do not understand how to lengthen the life of this value. It lives and dies in the list.iter(). How can I extend it while still only using references?
Here is my code for reference:
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for &item in list.iter() {
if item > *largest {
largest = &item;
}
}
largest
}
When you write for &item, this destructures each reference returned by the iterator, making the type of item T. You don't want to destructure these references, you want to keep them! Otherwise, when you take a reference to item, you are taking a reference to a local variable, which you can't return because local variables don't live long enough.
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
Note also how we can compare references directly, because references to types implementing PartialOrd also implement PartialOrd, deferring the comparison to their referents (i.e. it's not a pointer comparison, unlike for raw pointers).
Is there any way to get the slices of this vector to last long enough so that I can use them in this kind of circular structure?
fn populate_chain(file_path: &str) -> HashMap<String, HashSet<&String>> {
println!("loading...");
let time = util::StopWatch::new();
let mut words = HashMap::new();
{
let f = |mut x: Vec<String>| {
let word = x.pop().unwrap();
words.insert(word, HashSet::new());
};
Csv::process_rows(f, file_path, "\t");
}
let col: Vec<(String, HashSet<&String>)> = words.clone().into_iter().collect();
let m: usize = col.len() - 1;
for i in 0..m {
let ref k: String = col[i].0;
for j in i..m {
let ref nk: String = col[j].0;
if check_link(k, nk) {
words.get_mut(k).unwrap().insert(nk);
words.get_mut(nk).unwrap().insert(k);
}
}
}
time.print_time();
words
}
I'm using the double for loops to chain words together which are related so that they can be quickly looked up later.
Here are the compiler errors...
error: `col` does not live long enough
--> src/main.rs:28:29
|
28 | let ref k: String = col[i].0;
| ^^^ does not live long enough
...
40 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 13:72...
--> src/main.rs:13:73
|
13 | fn populate_chain(file_path: &str) -> HashMap<String, HashSet<& String>>{
| ^
error: `col` does not live long enough
--> src/main.rs:30:34
|
30 | let ref nk: String = col[j].0;
| ^^^ does not live long enough
...
40 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 13:72...
--> src/main.rs:13:73
|
13 | fn populate_chain(file_path: &str) -> HashMap<String, HashSet<& String>>{
|
I can tell you from your function signature that you're going to have big problems trying to write this function, at least if you want it to contain non-empty HashSets in the result.
fn populate_chain(file_path: &str) -> HashMap<String, HashSet<&String>>
This function signature has references in it; they have elided lifetimes. If you make the inferred lifetimes explicit, it would look like this:
fn populate_chain<'a>(file_path: &'a str) -> HashMap<String, HashSet<&'a String>>
In other words: This function claims that, given some string slice with lifetime 'a, it will give back a collection that holds String objects with lifetime 'a.
But you have no means for allocating such String objects within your code. :(
So, you're stuck; no matter what you put into that function body, you're not going to be able to supply an implementation that returns a non-trivial result with respect to the HashSets.
However, all is not lost. You could, for example, revise your function so that it also takes as an additional parameter a reference to a TypedArena with an appropriate lifetime, and then allocate the strings there. Another (simpler) option would be to use HashSet<String> instead of HashSet<&String>...