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

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

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)

Ghost new line and spaces added to String automatically in Rust

I created a empty Mutable String variable using String::new() before a loop start. Then I printed the string value as soon as I entered the loop, changed the type of the same variable to integer u32 by with user input, after trimming all spaces, \n, \r etc..
At the next Iteration of the loop, The value of the variable is back to String and was about to change its type, but when I checked the value of String by printing it, It had some ghost \n and spaces or some ghost characters inherited from the previous integer value.
if the integer is 3 digit, for eg 534 it has 5 characters
if the integer is 1 digit, for eg 3 it has 3 characters
if I give empty value as input, The parsing fails it stays as String, but still in next iteration the String has 2 characters.
I created a function to keep track of the type of variable.
use std::io;
//function to return type of a variable
fn type_of<T>(_: &T) -> String {
return format!("{}", std::any::type_name::<T>());
}
fn main() {
let mut guess = String::new();
loop {
println!(
"At start of loop : {},{}",
type_of(&guess),
guess.chars().count()
);
println!("value : {}", guess);
//emptying string
String::clear(&mut guess);
println!(
"after clearing : {},{}",
type_of(&guess),
guess.chars().count()
);
//getting input for string
println!("Enter value :");
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
//converted its values to interger u32 after trimming spaces,\n and \r and stuffs like that
let guess: u32 = match guess.trim().parse() {
Ok(a) => a,
Err(b) => {
println!("{}", b);
println!("after reciving error : {}", type_of(&guess));
continue;
}
};
println!("after type conversion : {}", type_of(&guess));
println!("value: {}", guess);
}
}
the output was :
At start of loop : alloc::string::String,0
value :
after clearing : alloc::string::String,0
Enter value :
111
after type conversion : u32
value: 111
At start of loop : alloc::string::String,5
value : 111
after clearing : alloc::string::String,0
Enter value :
1
after type conversion : u32
value: 1
At start of loop : alloc::string::String,3
value : 1
after clearing : alloc::string::String,0
Enter value :
cannot parse integer from empty string
after reciving error : alloc::string::String
At start of loop : alloc::string::String,2
value :
after clearing : alloc::string::String,0
Enter value :
What causes this?
Is there a way to maintain the value before the loop, at the start of every iteration?
or may be maintain the value of Integer from previous iteration and u32 Type at the same time?
I ran into this problem when I was trying to learn rust using "The Book" from rust docs, to be specific when I was trying to mess around with the code from Chapter 2 (Guess a number project).
There is a misunderstanding on how variables work in Rust. Different variables with the same name can exist, a process called shadowing. In this program, we have two variables called guess.
The following simplification of the previous code shows this pattern.
let guess: mut = String::new(); // <-- guess #1, lives outside loop
loop {
guess.clear();
println!("Enter value :");
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
// guess #2, lives inside loop
// vvvvv
let guess: u32 = match guess.trim().parse() {
Ok(a) => a,
Err(b) => {
eprintln!("{}", b);
continue;
}
};
println!("value: {}", guess);
}
The first one is always of type String, and the second one is always of type u32. Variables can never change type. What does change is which one can be seen and used in what scope. Since the second guess is only declared in the middle of the loop, mentioning guess before that declaration will mean the first guess, which is the string.
Combining the two facts that:
read_line reads and includes newline characters into the output string;
trim only returns a string slice, without modifying the underlying String value.
then it makes sense that guess will contain trailing newline characters at the beginning of the loop statement after the first iteration.
Is there a way to maintain the value before the loop, at the start of every iteration? or may be maintain the value of Integer from previous iteration and u32 Type at the same time?
With this last question rephrased to mean "a way to maintain the integer value from the previous iteration", then that is possible by giving it a new name and moving it up. In the example below, guess_num is reassigned on each iteration rather than declared each time.
let guess: mut = String::new();
let mut guess_num: u32 = 0;
loop {
println!("Previous number (or 0 if first iteration): {}", guess_num);
guess.clear();
println!("Enter value :");
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
guess_num = match guess.trim().parse() {
Ok(a) => a,
Err(b) => {
eprintln!("{}", b);
continue;
}
};
println!("value: {}", guess);
}
See also:
Why do I need rebinding/shadowing when I can have mutable variable binding?
How to ignore the line break while printing a string read from stdin?
The Rust Programming Language, 3.1 Variables and Mutability

How to provide range to RNG function in 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);

How to fix mismatched types when adding two Strings?

With a list input of &str, I'm trying to create a String which contains a proverb based on the inputs.
Instead of String::from I also tried .to_string() but that doesn't seem to help matters.
pub fn build_proverb(list: &[&str]) -> String {
let mut string = String::from(format!("For want of a {} the {} was lost.\n", list[0], list[1]));
if list.len() > 2 {
(3..list.len() + 1).map(|x| string = string + String::from(format!("For want of a {} the {} was lost.\n", list[x], list[x-1])));
}
string = string + &(format!("And all for the want of a {}.", list[0])).to_string();
return string.to_string();
}
The error is:
error: mismatched types expected &str, found struct 'std::string::String'.
This is on the String::from(format!("For want of a {} the {} was lost.\n", list[x], list[x-1])) line.
What's confusing to me is that I'm adding a String to a String - why is it expecting a &str?
format! already returns a String, so there's no need for String::from(format!(...)), and it's also an error because it expects a &str, not a String returned by format!.
You'll also get an error in the lambda:
string = string + String::from(format!(...))
...even if you remove String::from, because it's not possible to add two Strings like that, but it is possible to add a String and a &str, so I think you should borrow like this:
string = string + &format!(...)
The same goes for this line:
string = string + &(format!("And all for the want of a {}.", list[0])).to_string();
Moreover, your usage of map won't actually execute the lambda for each element of the range. It'll just create a Map iterator, over which you'll have to iterate with a loop to actually make it execute the lambda, so you could as well iterate over the range itself and modify your string in the loop.
I'm also not terribly sure about why you're returning string.to_string() when you could've returned string itself.
I also think you have an off-by-one error in your range, so after fixing that, I ended up with this:
fn do_it(list: Vec<&str>) -> String {
let mut string = format!("For want of a {} the {} was lost.\n", list[0], list[1]);
// BTW, you don't need this `if` statement because empty ranges, like `2..2`, are perfectly fine
if list.len() > 2 {
// These ranges do not include `list.len()`, so your program won't panic, because this index doesn't exist
for x in 2 .. list.len() {
string += &format!("For want of a {} the {} was lost.\n", list[x], list[x-1])
}
}
string + &format!("And all for the want of a {}.", list[0]) // Return the result of concatenation
}
fn main() {
let list = vec!["something", "test", "StackOverflow"];
let result = do_it(list);
println!("The result is: {}", result)
}
Output (it works, but your post doesn't say what it should output, so I can't say if it's the correct result):
The result is: For want of a something the test was lost.
For want of a StackOverflow the test was lost.
And all for the want of a something.

Rust String is not a String [duplicate]

This question already has answers here:
Why does my string not match when reading user input from stdin?
(3 answers)
Closed 6 years ago.
I use String::from("string") to get a String
let dog = String::from("dog")
and
dog == String::from("dog")
returns false. Even in pattern matching.
match dog.as_ref() {
"dog" => println!("Dog is a dog"), //no output
_ => println!("Dog is not a dog")
}
What is wrong?
Example
use std::io;
fn main() {
let mut sure = String::from("");
println!("Hello, world!");
println!("Are you sure(Y/N)");
io::stdin().read_line(&mut sure).expect("Failed");
println!("sure {}", sure );
let surely = {sure == String::from("Y")};
println!("surely {} ", surely ); //this line output is "surely false"
if surely {
dog_loop("HA");
}
}
As a general rule, when comparing Strings in Rust, it's better to turn the string into a &str for comparison against a string literal, rather than converting the string literal into a String. The reason for this is that the latter requires object creation (allocating for a String), while the first doesn't, and so it's more efficient.
The specific problem you are seeing here comes from the fact that your input does not have excess whitespace stripped. After the line
io::stdin().read_line(&mut sure).expect("Failed");
The value of sure is not "Y" as you might expect, but is actually "Y\n" on Unix, or "Y\r\n" on Windows. You can compare this directly by modifying your comparison as so:
let surely = {sure.as_str() == "Y\n"};
println!("surely {} ", surely );
And you will see it return "surely true". However, this makes your code platform-dependent. Preferably, use the string method String.trim(), which will remove the trailing whitespace.

Resources