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);
}
\$\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\$
    – Mast
    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.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.