String incrementer problem using rust (codewars) - rust

im trying to solve the string incrementer problem which is in codewars using rust
https://www.codewars.com/kata/54a91a4883a7de5d7800009c/train/rust
but when i wrote this code and ran . it came a error
error[E0599]: the method `to_string` exists for struct `Chars<'_>`, but its trait bounds were not satisfied
--> src/lib.rs:2:29
|
2 | let mut num = s.chars().to_string().filter(|c| "0123456789".contains(c)).collect();
| ^^^^^^^^^ method cannot be called on `Chars<'_>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Chars<'_>: std::fmt::Display`
which is required by `Chars<'_>: ToString`
error[E0599]: no method named `remove_last` found for reference `&str` in the current scope
--> src/lib.rs:4:11
|
4 | s.remove_last();
the real code is
fn increment_string(s: &str) -> String {
let mut num = s.chars().to_string().filter(|c| "0123456789".contains(c)).collect();
for i in 1..=num.len(){
s.remove_last();
}
num = num.chars().map(|c| c.parse::<u32>().unwrap()) + 1;
format!("{}{}",s,num);
}
can someone help me to rectify this error ?

Instead of let mut num = s.chars().to_string().filter(|c| "0123456789".contains(c)).collect(); you can write let mut num: String = s.chars().filter(|c| c.is_numeric()).collect();.
.pop() is used for removing the last element from the String
you don't need ; at the end of the function
Here is the working code (I've tested it on a few cases): https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=35d48393fa8ece9a2bb4cdc5c6544fcd
But you can still optimize it, I suppose ;)

Related

How do I use collect::<HashSet<_>>.intersection() without the values becoming borrowed?

I am looping loop over a Vec<&str>, each time reassigning a variable that holds the intersection of the last two checked. This is resulting in "expected char, found &char". I think this is happening because the loop is a new block scope, which means the values from the original HashSet are borrowed, and go into the new HashSet as borrowed. Unfortunately, the type checker doesn't like that. How do I create a new HashSet<char> instead of HashSet<&char>?
Here is my code:
use std::collections::HashSet;
fn find_item_in_common(sacks: Vec::<&str>) -> char {
let mut item: Option<char> = None;
let mut sacks_iter = sacks.iter();
let matching_chars = sacks_iter.next().unwrap().chars().collect::<HashSet<_>>();
loop {
let next_sack = sacks_iter.next();
if next_sack.is_none() { break; }
let next_sack_values: HashSet<_> = next_sack.unwrap().chars().collect();
matching_chars = matching_chars.intersection(&next_sack_values).collect::<HashSet<_>>();
}
matching_chars.drain().nth(0).unwrap()
}
and here are the errors that I'm seeing:
error[E0308]: mismatched types
--> src/bin/03.rs:13:26
|
6 | let matching_chars = sacks_iter.next().unwrap().chars().collect::<HashSet<_>>();
| ---------------------------------------------------------- expected due to this value
...
13 | matching_chars = matching_chars.intersection(&next_sack_values).collect::<HashSet<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `char`, found `&char`
|
= note: expected struct `HashSet<char>`
found struct `HashSet<&char>`
By the way, what is that first error trying to tell me? It seems like it is missing something before or after "expected" -- <missing thing?> expected <or missing thing?> due to this value?
I also tried changing matching_chars = matching_chars to matching_chars = matching_chars.cloned() and I get the following error. I understand what the error is saying, but I don't know how to resolve it.
error[E0599]: the method `cloned` exists for struct `HashSet<char>`, but its trait bounds were not satisfied
--> src/bin/03.rs:13:41
|
13 | matching_chars = matching_chars.cloned().intersection(&next_sack_values).collect::<HashSet<_>>();
| ^^^^^^ method cannot be called on `HashSet<char>` due to unsatisfied trait bounds
|
::: /Users/brandoncc/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/collections/hash/set.rs:112:1
|
112 | pub struct HashSet<T, S = RandomState> {
| -------------------------------------- doesn't satisfy `HashSet<char>: Iterator`
|
= note: the following trait bounds were not satisfied:
`HashSet<char>: Iterator`
which is required by `&mut HashSet<char>: Iterator`
Your attempt at using cloned() was almost right but you have to call it after you create the iterator:
matching_chars.intersection(&next_sack_values).cloned().collect::<HashSet<_>>()
or for Copy types you should use the more appropriate .copied() adapter:
matching_chars.intersection(&next_sack_values).copied().collect::<HashSet<_>>()
Looking at the signature of HashSet::intersection will make this clearer:
pub fn intersection<'a>(
&'a self,
other: &'a HashSet<T, S>
) -> Intersection<'a, T, S>
The type Intersection<'a, T, S> implements Iterator<Item=&'a T>. So when you collect this iterator, you get a HashSet<&char> as opposed to a HashSet<char>.
The solution is simply to use .cloned on the iterator before you use .collect, since char is Clone, like so:
matching_chars = matching_chars.intersection(&next_sack_values).cloned().collect()
By the way, what is that first error trying to tell me?
The error is telling you that it expects char because (due to) the original value for matching_chars has type HashSet<char>.
I also tried changing matching_chars = matching_chars to matching_chars = matching_chars.cloned() and I get the following error. I understand what the error is saying, but I don't know how to resolve it.
Do you, really?
str::chars is an Iterator<Item=char>, so when you collect() to a hashset you get a HashSet<char>.
The problem is that intersection borrows the hashset, and since the items the hashset contains may or may not be Clone, it also has to borrow the set items, it can't just copy or clone them (not without restricting its flexibility anyway).
So that's where you need to add the cloned call, on the HashSet::intersection in order to adapt it from an Iterator<Item=&char> to an Iterator<Item=char>.
Or you can just use the & operator, which takes two borrowed hashsets and returns an owned hashset (requiring that the items be Clone).
Alternatively use Iterator::filter or Iterator::findon one of the sets, checking if the othersHashSet::containsthe item being looked at. Fundamentally that's basically whatintersection` does, and you know there's just one item at the end.

Rust: Error[E0277]: the trait bound `{integer}: SampleRange<_>` is not satisfied

I have a line of code that is in a for loop, and it's supposed to generate a random number from 0 to 2499. It is giving me problems.
let index = rand::thread_rng().gen_range(2499);
Full code for those who want to know:
fn generate_phrase () -> String {
let mut phrase = String::new();
let mut file = File::open("words.txt").expect("Failed to open words.txt");
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Failed to read words.txt");
let words: Vec<&str> = contents.split("\n").collect();
for _ in 0..8 {
let index = rand::thread_rng().gen_range(2499);
phrase.push_str(words[index]);
phrase.push(' ');
}
println!("Your phrase is: {:?}", phrase);
return phrase;
}
Error message:
error[E0277]: the trait bound `{integer}: SampleRange<_>` is not satisfied
--> src/crypto/crypto.rs:115:45
|
115 | let index = rand::thread_rng().gen_range(2499);
| --------- ^^^^ the trait `SampleRange<_>` is not implemented for `{integer}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `gen_range`
--> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\rand-0.8.5\src\rng.rs:132:12
|
132 | R: SampleRange<T>
| ^^^^^^^^^^^^^^ required by this bound in `gen_range
I know the problem, which is that the trait is not the right kind but I don't know how to convert the integer into the necessary trait: SampleRange<T>. I've looked on StackOverFlow and couldn't find an appropriate answer anywhere.
The SampleRange that it complains about can be either a Range or RangeInclusive, rather than just an upper-bound (see the "implementations" section in SampleRange to see which types implement the trait). All you need is to change that one line to look something like this:
let index = rand::thread_rng().gen_range(0..2499);

Partition over Vec<Result<T, E>> fails due to type mismatch

I'm attempting to collect a series of calculations which can fail into two vectors, one containing the successful calculations and one containing any errors.
I can instantiate the vector Vec<Result<T, E>> but calling partition fails to compile.
Example code:
fn main() {
let f:Result<i32, String> = Err("a".to_owned());
let s:Result<i32, String> = Ok(5);
let v:Vec<Result<i32, String>> = vec![f, s];
// works
dbg!(&v[0]);
dbg!(&v[1]);
// fails
let (sp, fp):(Vec<_>, Vec<_>) = v.iter().partition(Result::is_ok);
dbg!(sp);
dbg!(fp);
}
Error below:
error[E0631]: type mismatch in function arguments
--> src/main.rs:12:56
|
12 | let (sp, fp):(Vec<_>, Vec<_>) = v.iter().partition(Result::is_ok);
| --------- ^^^^^^^^^^^^^
| | |
| | expected signature of `for<'r> fn(&'r &Result<i32, String>) -> _`
| | found signature of `for<'r> fn(&'r Result<_, _>) -> _`
| required by a bound introduced by this call
Based on the rust by example docs this seems like it should be doable - what am I missing?
iter() returns an iterator over references, and partition() takes a callback that takes a reference - that's two references. Result::is_ok(), however, takes &self with one reference.
You can either use into_iter() or provide a closure that takes two references: .partition(|result| result.is_ok()).

Passing String::as_str to Option<String>::map() fails to compile with a type mismatch error [duplicate]

This question already has an answer here:
Why does Option<String>.as_ref() not deref to Option<&str>?
(1 answer)
Closed 3 years ago.
The second map statement in this code fails to compile.
fn main() {
let hello = Some("hello");
let _switcheroo = hello.map(str::to_string); //ok
let hello = Some("hello".to_string());
let _switcheroo = hello.map(String::as_str); //not ok
}
The error is:
error[E0631]: type mismatch in function arguments
--> src/main.rs:6:29
|
6 | let _switcheroo = hello.map(String::as_str); //not ok
| ^^^
| |
| expected signature of `fn(std::string::String) -> _`
| found signature of `for<'r> fn(&'r std::string::String) -> _`
I would expect an error about borrowing some moved data. What is this error trying to say?
This does compile:
let hello = Some("hello".to_string());
let _switcheroo = hello.as_ref().map(String::as_str); //ok
The problem is that String::as_str expects a reference to a String rather than the String itself. String::as_str's signature is fn as_str(&self) -> &str, so you can see that it takes self (the String) as a reference.
To interpret the error message, look at the "expected" vs "found". In the "expected" part of the message, we see fn(std::string::String) -> _, so it's expecting a function that takes std::string::String (i.e. String) and returns some irrelevant type (_). In the "found" part of the message however, we find for<'r> fn(&'r std::string::String) -> _. This is harder to understand since it uses an idea that's rarely seen in Rust code.
The for<'r> part means that the function should be generic with respect to the lifetime. It should accept any lifetime and a String with that lifetime. The output type can also have the given lifetime. Usually a function like this has a signature like fn foo(x: &T) -> &U and the lifetimes are implicitly added. This is exactly what String::as_str is.
One way to fix your code is to ensure that a reference is passed to map. Something like let _switcheroo = hello.as_ref().map(String::as_str); should work.

How do I parse a vector into a function?

The idea is to send a set of characters of a vector and let the function display the current correct guesses.
Here is my main:
fn main() {
let mut guessedLetters = vec![];
displayWord(guessedLetters);
}
And here is the function:
fn displayWord(correctGuess: Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
I don't know what I'm supposed to write inside the parameters of displayWord.
There's a couple of things wrong with your code.
The first error is pretty straight forward:
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ expected char, found enum `std::option::Option`
|
= note: expected type `std::vec::Vec<char>`
found type `std::vec::Vec<std::option::Option<char>>`
The function you wrote is expecting a vector a characters ... but you're passing it a vector of Option<char>. This is happening here:
guessed_Letters.push(line.chars().nth(0));
According to the documentation, the nth method returns an Option. The quick fix here is to unwrap the Option to get the underlying value:
guessed_Letters.push(line.chars().nth(0).unwrap());
Your next error is:
error[E0382]: use of moved value: `guessed_Letters`
--> src/main.rs:38:25
|
38 | displayWord(guessed_Letters);
| ^^^^^^^^^^^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `guessed_Letters` has type `std::vec::Vec<char>`, which does not implement the `Copy` trait
This is transferring ownership of the vector on the first iteration of the loop and the compiler is telling you that subsequent iterations would be in violation of Rust's ownership rules.
The solution here is to pass the vector by reference instead:
displayWord(&guessed_Letters);
..and your method should also accept a reference:
fn displayWord(correctGuess: &Vec<char>) {
let mut currentWord = String::new();
for x in 0..5 {
currentWord.push(correctGuess[x]);
}
println!("Current guesses: {}", currentWord);
}
This can be shortened to use a slice and still work:
fn displayWord(correctGuess: &[char]) {

Resources