How to provide range to RNG function in Rust? - rust

I'm new to programming and I got stucked with Guessing Game tutorial exercise. I'm trying to provide a range to the RNG function but I'm probably doing it wrong. I read the whole documentation but I didn't find a solution to my issue.
The idea is very simple :
Player choose a difficulty level
Each difficulty level matches a range
RNG function pick a number within this range
Here is the code I wrote :
use rand::Rng;
fn main() {
println!("\nChoississez votre niveau de difficulté\n
A- Facile\n
B- Normale\n
C- Difficile\n");
let difficulte: String = read!();
let intervalle = match difficulte.as_str() {
"A" => 1..=10,
"B" => 1..=100,
"C" => 1..=1000,
_ => 1..=10000,
};
println!("\nDécouvrez un nombre entre {} et {}", intervalle.start(), intervalle.end());
let secret_number= rand::thread_rng().gen_range(intervalle.start()..intervalle.end());
println!("secret number {}", secret_number);
}
I get an error for that line (everything after gen.range) :
let secret_number= rand::thread_rng().gen_range(intervalle.start()..intervalle.end());
Here is the error :
the trait bound &{integer}: rand::distributions::uniform::SampleUniform is not satisfied
the trait rand::distributions::uniform::SampleUniform is not implemented for &{integer}
If I change intervalle.start() and intervalle.end() by actual numbers (1 and 100 for example) everything is working fine.
What am I doing wrong ?
Thank you for your help

The problem is that the start and end methods return references and not values, i.e. a &i32 and not a i32. You could fix this by just dereferencing the return values:
let secret_number = rand::thread_rng().gen_range(*intervalle.start()..*intervalle.end());
// ^ ^
* is the dereferencing operator.
Instead of constructing a range and storing it in intervalle just to use that range's bounds to construct another range, though, you can just pass intervalle to gen_range directly!
let secret_number = rand::thread_rng().gen_range(intervalle);

Related

Check serde_json Value for value with key sets of arbitrary depth or add if null Rust

With something like the vec below Id like to add arbitrary depth to a json object.
let set = vec![vec!["123","apple","orange","999"],vec!["1234","apple"],vec!["12345","apple","orange"]];
Once created the above would look something like:
{"123":{"apple":{"orange":"999"}}, "1234":"apple", "12345":{"apple":"orange"}}
Ive tried recursion, the issue Im running into is that Im having trouble reasoning through it. The wall Ive hit is how do I refer up the chain of values?
Is there a method Im missing here? Surely Im not the only person whos wanted to do this...
I would prefer if at all possible not writing something cumbersome that takes the length of a key set vec and matches creating the nesting ex.:
match keys.len() {
2 => json_obj[keys[0]] = json!(keys[1]),
3 => json_obj[keys[0]][keys[1]] = json!(keys[2]),
4 => json_obj[keys[0]][keys[1]][keys[2]] = json!(keys[3]),
...
_=> ()
}
Any ideas?
You can do this with iteration -- each loop you walk deeper into the structure, and further into the iterator, but the trick is that each step you need to know if there are more elements beyond the final one because the final element needs to be a string instead of an object. We'll do this using a match construct that matches on the next two items in the sequence at once.
We can further generify the function to take "anything that can be turned into an iterator that produces items from which we can obtain a &str". This will accept both an iterator of String or an iterator of &str, for example, or even directly a Vec of either.
use std::borrow::Borrow;
use serde_json::Value;
fn set_path(
mut obj: &mut Value,
path: impl IntoIterator<Item=impl Borrow<str>>
) {
let mut path = path.into_iter();
// Start with nothing in "a" and the first item in "b".
let mut a;
let mut b = path.next();
loop {
// Shift "b" down into "a" and put the next item into "b".
a = b;
b = path.next();
// Move "a" but borrow "b" because we will use it on the next iteration.
match (a, &b) {
(Some(key), Some(_)) => {
// This level is an object, rebind deeper.
obj = &mut obj[key.borrow()];
}
(Some(s), None) => {
// This is the final string in the sequence.
*obj = Value::String(s.borrow().to_owned());
break;
}
// We were given an empty iterator.
(None, _) => { break; }
}
}
}
(Playground)

how to bool a string contains a digit between an another digit

I want to know if it possible to boolean a String contains a digit between an another digit
to set a variable after
the code i tried
pub fn ram() -> String {
let okmdr = Command::new("wmic").arg("memorychip").arg("get").arg("speed").output().unwrap_or_else(|e| panic!("impossible d'obtenir le type et la vitesse de la RAM"));
let speed = String::from_utf8_lossy(&okmdr.stdout).to_string();
let split: Vec<String> = speed.split_inclusive("Speed").map(|s| s.to_string()).collect();
let splitjsp: Vec<String> = split[1].split(" ").map(|o| o.to_string()).collect();
let jsp = if splitjsp[2].contains(1601..3200) { String::from("DDR4") } else if splitjsp[2].contains(0..1600) { String::from("DDR3") } else { String::from("Unknown")};
jsp
}
the error i got :
let jsp = if splitjsp[2].contains(1601..3200) { String::from("DDR4") } else if splitjsp[2].contains(0..1600) { String::from("DDR3") }...
-------- ^^^^^^^^^^ expected an `FnMut<(char,)>` closure, found `std::ops::Range<{integer}>`
|
required by a bound introduced by this call
Your English is a bit garbled, so let me see if I got that right: You want to check if some number is contained in an interval, but that number is currently stored in a string?
Well, currently your code is calling str::contains which can check whether a string contains e.g. a substring or character. For example, you can test whether "sd" is contained in "asdf" (yes). That is not what you want.
You'll have to use
str::parse
Range::contains
Do note that a Rust range a..b contains a, but doesn't contain b. If you want a range that contains both ends, you want a..=b.
So you might do something like:
let jsp2 = splitjsp[2].parse().expect("JSP output format: expected integer in line 3");
if (1601..=3200).contains(&jsp2) {
…
but it might be more elegant to use a match:
match jsp2 {
0..1601 => …,
1601..3201 => …,
_ => …,
}
Playground

What is & doing in a rust for in loop? [duplicate]

This question already has an answer here:
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
Closed 1 year ago.
Trying to understand how & works in a rust for..in loop...
For example let's say we have something simple like a find largest value function which takes a slice of i32's and returns the largest value.
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for item in list {
if *item > largest {
largest = *item;
}
}
largest
}
In the scenario given above item will be an &i32 which makes sense to me. We borrow a slice of i32's and as a result the item would also be a reference to the individual item in the slice. At this point we can dereference the value of item with * which is what I assume how a pointer based language would work.
But now if we alter this slightly below...
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}
If we put an & in front of item this changes item within the for..in into an i32... Why? In my mind this is completely counterintuitive to how I would have imagined it to work. This to me says, "Give me an address/reference to item"... Which in itself would already be a reference. So then how does item get dereferenced? Is this just a quirk with rust or am I fundamentally missing something here.
All variable assignments in Rust, including loop variables in for loops and function arguments, are assigned using pattern matching. The value that is being assigned is matched against the target pattern, and Rust tries to fill in the "blanks", i.e. the target variable names, in a way that substituting the values makes the pattern match the value. Let's look at a few examples.
let x = 5;
This is the simplest case. Obvious, substituting x with 5 makes both sides match.
if let Some(x) = Some(5) {}
Here, x will also become 5, since substituting that value into the pattern will make both side identical.
let &x = &5;
Again, the two sides match when setting x to 5.
if let (Some(&x), &Some(y)) = (Some(&5), &Some(6)) {}
This assignment results in x = 5 and y = 6, since substituting these values into the pattern makes both sides match.
Let's apply this to your for loop. In each loop iteration, the pattern after for is matched against the next value returned by the iterator. We are iterating an &[i32], and the item type of the resulting iterator is &i32, so the iterator yields a &i32 in each iteration. This reference is matched against the pattern &item. Applying what we have seen above, this means item becomes an i32.
Note that assigning a value of a type that does not have the Copy marker trait will move that value into the new variable. All examples above use integers, which are Copy, so the value is copied instead.
There is no magic here, pure logic. Consider this example:
let a = 1;
let b = &a; // b is a reference to a
let &c = &a; // c is a copy of value a
You can read the third line of the example above as "Assign reference to a to a reference to c". This basically creates a virtual variable "reference to c", assigns to it the value &a and then dereferences it to get the value of c.
let a = 1;
let ref_c = &a;
let c = *ref_c;
// If you try to go backwards into this assignments, you get:
let &c = &a;
let &(*ref_c) = &a;
let ref_c = &a; // which is exactly what it was
The same occurs with the for .. in syntax. You iterate over item_ref, but assign them to &item, which means that the type of item is Item.
for item_ref in list {
let item = *item_ref;
...
}
// we see that item_ref == &item, so above is same as
for &item in list {
...
}

String equality in Rust: how does referencing and dereferencing work?

As a Rust newbie, I'm working through the Project Euler problems to help me get a feel for the language. Problem 4 deals with palindromes, and I found two solutions for creating a vector of palindromes, but I'm not sure how either of them work.
I'm using a vector of strings, products, that's calculated like this:
let mut products = Vec::new();
for i in 100..500 {
for j in 500..1000 {
products.push((i * j).to_string());
}
}
For filtering these products to only those that are palindromic, I have the following two solutions:
Solution 1:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| x == &x.chars().rev().collect::<String>())
.collect();
Solution 2:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| *x == *x.chars().rev().collect::<String>())
.collect();
They both yield the correct result, but I have no idea why!
In Solution 1, we're comparing a reference of a string to a reference of a string we've just created?
In Solution 2, we dereference a reference to a string and compare it to a dereferenced new string?
What I would expect to be able to do:
let palindromes: Vec<_> = products
.iter()
.filter(|x| x == x.chars().rev().collect::<String>())
.collect();
I'm hoping somebody will be able to explain to me:
What is the difference is between my two solutions, and why do they both work?
Why can't I just use x without referencing or dereferencing it in my filter function?
Thank you!
Vec<String>.iter() returns an iterator over references (&String).
The closure argument of .filter() takes a reference to an iterator's item. So the type that is passed to the closure is a double reference &&String.
|&x| tells the closure to expect a reference, so x is now of type &String.
First solution: collect returns a String, of which & takes the reference. x is also a reference to a string, so the comparison is between two &String.
Second solution: The dereference operator * is applied to x, which results in a String. The right hand side is interesting: The String result of collect is dereferenced. This results in a string slice because String implements Deref<Target=str>. Now the comparison is between String and str, which is works because it is implemented in the standard library (Note that a == b is equivalent to a.eq(&b)).
Third solution: The compiler explains why it does not work.
the trait std::cmp::PartialEq<std::string::String> is not implemented for &&std::string::String
The left side is a double reference to string (&&String) and the right side is just a String . You need to get both sides to the same "reference level". All of these work:
x.iter().filter(|x| x == &&x.chars().rev().collect::<String>());
x.iter().filter(|x| *x == &x.chars().rev().collect::<String>());
x.iter().filter(|x| **x == x.chars().rev().collect::<String>());

How to end a borrow in a match or if let expression?

I am using a HashMap to store an enum. I'd like to get a value from the HashMap and if the value is a specific enum variant, I'd like to insert a modified copy of the value back in the HashMap.
The code I came up with looks like this:
if let Node::LeafNode(mut leaf_node) = *(self.pages.get(&page).unwrap()) {
let mut leaf_node = leaf_node.clone();
// ...
self.pages.insert(leaf_page,Node::LeafNode(leaf_node));
}
This does not compile because the borrow of self.pages lasts until the end of the if let-block and self.pages.insert is a mutable borrow.
I have tried to shadow the value of the HashMap with a copy of the value, but this does not end the borrow. Usually I would use a {} block to limit the borrow, but this seems to be not possible in match or if let.
What is the idiomatic way to end a borrow so that I can get a new mutable borrow?
This is not possible at the moment. What you want is called non-lexical borrows and it is yet to be implemented in Rust. Meanwhile, you should use Entry API to work with maps - in most cases it should be sufficient. In this particular case I'm not sure if entries are applicable, but you can always do something like
let mut result = None;
if let Some(&Node::LeafNode(ref leaf_node)) = self.pages.get(&page) {
let mut leaf_node = leaf_node.clone();
// ...
result = Some((leaf_page, leaf_node));
}
if let Some((leaf_page, leaf_node)) = result {
self.pages.insert(leaf_page, leaf_node);
}
It is difficult to make the code above entirely correct given that you didn't provide definitions of Node and self.pages, but it should be approximately right. Naturally, it would work only if leaf_page and leaf_node do not contain references to self.pages or self, otherwise you won't be able to access self.pages.
Here is Vladimir's solution using match:
let mut result = match self.pages.get(&page) {
Some(&Node::LeafNode(ref leaf_node)) => Some(leaf_node.clone()),
_ => None,
};
if let Some(leaf_node) = result {
// ...
self.pages.insert(page_number, Node::LeafNode(leaf_node));
};

Resources