I'm trying to write the Rust equivalent of the following C++ code:
result += consonants[rand() % consonants.length()];
It is meant to take a random character from the string consonants
and append it to the string result
.
I seem to have found a working Rust equivalent, but it's... monstrous, to say the least. What would be a more idiomatic equivalent?
format!("{}{}", result, consonants.chars().nth(rand::thread_rng().gen_range(1, consonants.chars().count())).unwrap().to_string());
A few things:
You don't need to use
format!()
here. There isString::push()
which appends a single char.There is also the
rand::sample()
function which can randomly choose multiple elements from an iterator. This looks like the perfect fit!So let's see how this fits together! I created three different versions for different use cases.
1. Unicode string (the general case)
(Playground)
We sample only one element from the iterator and immediately push it to the string. Still not as short as with C's
rand()
, but please note thatrand()
is considered harmful for any kind of serious use! Using C++'s<random>
header is a lot better, but will require a little bit more code, too. Additionally, your C version can't handle multi-byte characters (e.g. UTF-8 encoding), while the Rust version has full UTF-8 support.2. ASCII string
However, if you only want to have a string with English consonants, then UTF-8 is not needed and we can make use of O(1) indexing, by using a byte slice:
(Playground)
3. Collection of characters with Unicode support
As mentioned in the comments, you probably just want a collection of characters ("consonants"). This means, we don't have to use a string, but rather an array of
chars
. So here is one last version which does have UTF-8 support and avoids O(n) indexing:(Playground)