How to split a string in Rust with multiple parameters? - rust

I am trying to split a string in Rust using both whitespace and ,. I tried doing
let v: Vec<&str> = "Mary had a little lamb".split_whitespace().collect();
let c: Vec<&str> = v.split(',').collect();
The result:
error[E0277]: the trait bound `for<'r> char: std::ops::FnMut<(&'r &str,)>` is not satisfied
--> src/main.rs:3:26
|
3 | let c: Vec<&str> = v.split(',').collect();
| ^^^^^ the trait `for<'r> std::ops::FnMut<(&'r &str,)>` is not implemented for `char`
error[E0599]: no method named `collect` found for type `std::slice::Split<'_, &str, char>` in the current scope
--> src/main.rs:3:37
|
3 | let c: Vec<&str> = v.split(',').collect();
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`std::slice::Split<'_, &str, char> : std::iter::Iterator`
`&mut std::slice::Split<'_, &str, char> : std::iter::Iterator`

Use a closure:
let v: Vec<&str> = "Mary had a little lamb."
.split(|c| c == ',' || c == ' ')
.collect();
This is based upon the String documentation.

Pass a slice with the chars to it:
fn main() {
let s = "1,2 3";
let v: Vec<_> = s.split([' ', ','].as_ref()).collect();
assert_eq!(v, ["1", "2", "3"]);
}
split takes an argument of type Pattern. To see what concretely you can pass as parameter, see the implementors

Related

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);

What's the purpose of ".map(|&x| x)" in Rust

I'm learning Rust and noticed the following iterator pattern in a number of places:
let some_vector: &[& str] = &["hello", "world", "zombies", "pants"];
let result: Vec<&str> = some_vector
.iter()
.filter(|&x| *x == "hello")
.map(|&x| x)
.collect();
What's the purpose of that .map(|&x| x)? Why is it necessary? Does it create a copy?
When I remove it, I get the following compiler error:
error[E0277]: a value of type `Vec<&str>` cannot be built from an iterator over elements of type `&&str`
--> src/main.rs:7:6
|
7 | .collect();
| ^^^^^^^ value of type `Vec<&str>` cannot be built from `std::iter::Iterator<Item=&&str>`
|
= help: the trait `FromIterator<&&str>` is not implemented for `Vec<&str>`
note: required by a bound in `collect`
For more information about this error, try `rustc --explain E0277`.
So the map turns an iterator over references to string slices into an iterator over string slices? Removing one level of indirection? Is that right?
In addition to #AlexW's answer, actually there is no need to write that, because there is a builtin iterator adapter that does it better (more clear, more performant): copied().
let some_vector: &[&str] = &["hello", "world", "zombies", "pants"];
let result: Vec<&str> = some_vector
.iter()
.filter(|&x| *x == "hello")
.copied()
.collect();
There is also cloned() which is equal to .map(|x| x.clone()).
Assuming you're using 2021 edition, it converts from impl Iterator< Item = &&str> to impl Iterator< Item = &str>:
let some_vector: &[& str] = &["hello", "world", "zombies", "pants"];
let result: Vec<&str> = some_vector // &[&str]
.iter() // Iter<&str>
.filter(|&x| *x == "hello") // Impl Iterator< Item = &&str>
.map(|&x| x) // Impl Iterator< Item = &str>
.collect();
And the reason it's necessary is because the FromIterator trait is already implemented for &str as it's a relatively more common use case and it's not implemented for &&str as the error message says:
the trait `FromIterator<&&str>` is not implemented for `Vec<&str>`

How do I convert a Vec<MyStruct> to a Vec<String> then to a Vec<&str> in a single step? [duplicate]

This question already has answers here:
Return local String as a slice (&str)
(7 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
How do I convert a Vec<String> to Vec<&str>?
(6 answers)
Closed 3 years ago.
I am trying to convert a Vec of a given struct to its String and eventually to &str format.
This example code simulates exactly what I am trying to achieve.
fn main() {
let a = vec![1i32, 2i32, 3i32];
let step1: Vec<String> = a.iter().map(|x| x.to_string()).collect::<Vec<String>>();
let step2: Vec<&str> = step1.iter().map(AsRef::as_ref).collect::<Vec<&str>>();
// This does not work as I was expecting it to
// and its not being accepted by the compiler as valid code
//
let in_single_step: Vec<&str> = a
.iter()
.map(|x| x.to_string()) // <--- Something is needed after this step?
.map(AsRef::as_ref)
.collect::<Vec<&str>>();
println!("{:?}", in_single_step);
}
playground with this code
I get an error:
error[E0631]: type mismatch in function arguments
--> src/main.rs:14:10
|
14 | .map(AsRef::as_ref)
| ^^^
| |
| expected signature of `fn(std::string::String) -> _`
| found signature of `for<'r> fn(&'r _) -> _`
error[E0599]: no method named `collect` found for type `std::iter::Map<std::iter::Map<std::slice::Iter<'_, i32>, [closure#src/main.rs:13:14: 13:31]>, for<'r> fn(&'r _) -> &'r _ {<_ as std::convert::AsRef<_>>::as_ref}>` in the current scope
--> src/main.rs:15:10
|
15 | .collect::<Vec<&str>>();
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`&mut std::iter::Map<std::iter::Map<std::slice::Iter<'_, i32>, [closure#src/main.rs:13:14: 13:31]>, for<'r> fn(&'r _) -> &'r _ {<_ as std::convert::AsRef<_>>::as_ref}> : std::iter::Iterator`
`std::iter::Map<std::iter::Map<std::slice::Iter<'_, i32>, [closure#src/main.rs:13:14: 13:31]>, for<'r> fn(&'r _) -> &'r _ {<_ as std::convert::AsRef<_>>::as_ref}> : std::iter::Iterator`
Similar questions are:
Convert Vec<String> to Vec<&str>
Convert Vec<String> into a slice of &str in Rust?

How to convert u8 to &[u8] in Rust? [duplicate]

This question already has answers here:
Converting number primitives (i32, f64, etc) to byte representations
(5 answers)
Closed 3 years ago.
I am new and lost in Rust a bit.
I would like to add keys and values to a data store that has a put function that takes two byte string literals:
batch.put(b"foxi", b"maxi");
I generate a bunch of these k-v pairs:
for _ in 1..1000000 {
let mut ivec = Vec::new();
let s1: u8 = rng.gen();
let s2: u8 = rng.gen();
ivec.push(s1);
ivec.push(s2);
debug!("Adding key: {} and value {}", s1, s2);
vec.push(ivec);
}
let _ = database::write(db, vec);
I have a fn that tries to add them:
pub fn write(db: DB, vec: Vec<Vec<u8>>) {
let batch = WriteBatch::new();
for v in vec {
batch.put(v[0], v[1]);
}
db.write(&batch).unwrap();
}
When I try to compile this I get:
error[E0308]: mismatched types
--> src/database.rs:17:19
|
17 | batch.put(v[0], v[1]);
| ^^^^ expected &[u8], found u8
|
= note: expected type `&[u8]`
found type `u8`
error[E0308]: mismatched types
--> src/database.rs:17:25
|
17 | batch.put(v[0], v[1]);
| ^^^^ expected &[u8], found u8
|
= note: expected type `&[u8]`
found type `u8`
I was ping-ponging with the borrow checker for a while now but I could not get it working. What is the best way to have byte literal strings from u8s?
The following works:
batch.put(&v[0].as_bytes(), &v[1].as_bytes())

How can a range be used in a Vec?

This code works fine:
fn main() {
let v: i32 = vec![1, 2, 3, 4, 5].iter().map(|&x: &i32| x.pow(2)).sum();
println!("{}", v);
}
I tried to replace the vec![1, 2, 3, 4, 5] with vec![1..5] but iter and map did not work:
error[E0631]: type mismatch in closure arguments
--> src/main.rs:2:36
|
2 | let v: i32 = vec![1..5].iter().map(|&x: &i32| x.pow(2)).sum();
| ^^^ ------------------- found signature of `for<'r> fn(&'r i32) -> _`
| |
| expected signature of `fn(&std::ops::Range<{integer}>) -> _`
error[E0599]: no method named `sum` found for type `std::iter::Map<std::slice::Iter<'_, std::ops::Range<{integer}>>, [closure#src/main.rs:2:40: 2:59]>` in the current scope
--> src/main.rs:2:61
|
2 | let v: i32 = vec![1..5].iter().map(|&x: &i32| x.pow(2)).sum();
| ^^^
|
= note: the method `sum` exists but the following trait bounds were not satisfied:
`std::iter::Map<std::slice::Iter<'_, std::ops::Range<{integer}>>, [closure#src/main.rs:2:40: 2:59]> : std::iter::Iterator`
`&mut std::iter::Map<std::slice::Iter<'_, std::ops::Range<{integer}>>, [closure#src/main.rs:2:40: 2:59]> : std::iter::Iterator`
I've also asked this question on the Rust user's forum.
A range like 1..5 is already an iterator, so you do not have to call iter() to create one:
let v: i32 = (1..5).map(|x: i32| x.pow(2)).sum();
Also note that the references are gone because this iterator iterates over values.
If you absolutly need a Vec, you need to collect the range into it first:
let v: i32 = (1..5)
.collect::<Vec<i32>>()
.iter()
.map(|&x: &i32| x.pow(2))
.sum();

Resources