2
\$\begingroup\$

This is my implementation of the Pig Latin recommended exercise in The Rust Programming Language book. Any pointers on making this code more idiomatic or run more optimal?

fn pig_latin() {
 let s = String::from("Some abobus string 32 text привет абоба 123");
 let mut new_s = s.clone();
 let consonant = Vec::from([
 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r',
 's', 't', 'v', 'w', 'x', 'y', 'z', 'б', 'в', 'г', 'д', 'ж', 'з', 'й',
 'к', 'л', 'м', 'н', 'п', 'р', 'с', 'т', 'ф', 'х', 'ц', 'ч', 'ш', 'щ'
 ]); // Согласные
 for word in s.split_whitespace() {
 let chars = word.chars();
 if let Some(ch) = chars.peekable().peek() {
 if ch.is_alphabetic() {
 if consonant.contains(ch.to_lowercase().peekable().peek().map_or(ch, |v| v )) {
 new_s = new_s.replace(word, &format!("{}-{}ay", &word[ch.len_utf8()..word.len()], ch));
 } else {
 new_s = new_s.replace(word, &format!("{}-hay", &word[0..word.len()]));
 }
 }
 }
 }
 println!("Old: '{}' \nNew: '{}'", s, new_s);
}
Mast
13.8k12 gold badges56 silver badges127 bronze badges
asked Oct 19, 2021 at 21:29
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers . \$\endgroup\$ Commented Nov 7, 2021 at 16:42

1 Answer 1

3
\$\begingroup\$
let consonant = Vec::from([
 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r',
 's', 't', 'v', 'w', 'x', 'y', 'z', 'б', 'в', 'г', 'д', 'ж', 'з', 'й',
 'к', 'л', 'м', 'н', 'п', 'р', 'с', 'т', 'ф', 'х', 'ц', 'ч', 'ш', 'щ'
]);

An alternative would be:

fn is_consonant(character: char) -> bool {
 matches!(character, 'b' | 'c' | ...)
}

My theory would be that Rust probably generated somewhat better code against a pattern match as compared to searching a vector.

 let chars = word.chars();
 if let Some(ch) = chars.peekable().peek() {

There doesn't seem to be any reason to use peekable here. Just use word.chars.next().

 if consonant.contains(ch.to_lowercase().peekable().peek().map_or(ch, |v| v )) {

You don't need peekable here either. I would also probably not use map_or but instead unwrap. My theory would be that to_lowercase is never going to return an empty string, so next or peek should always return something. If it doesn't, I don't think falling back to ch makes sense.

 new_s = new_s.replace(word, &format!("{}-{}ay", &word[ch.len_utf8()..word.len()], ch));

This is wrong. You replace the whole string, but its very possible that the word appears other places in the string and will give you odd results.

answered Nov 5, 2021 at 10:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.