0
\$\begingroup\$

I just finished the chapter about collections from the Rust book, and it recommended trying some exercises provided there, such as a Pig Latin translator.

Convert strings to pig latin. The first consonant of each word is moved to the end of the word and “ay” is added, so “first” becomes “irst-fay.” Words that start with a vowel have “hay” added to the end instead (“apple” becomes “apple-hay”). Keep in mind the details about UTF-8 encoding!

use std::io;
fn main() {
    let mut inp = String::new();
    io::stdin().read_line(&mut inp).expect("Could not read");
    inp.remove(inp.len() - 1); // newline
    let cha = inp.chars().next().expect("Empty string");
    if is_consonant(cha) {
        inp += "-hay";
    } else {
        inp.remove(0);
        inp += &format!("-{}ay", cha);
    }
    println!("{}", inp);
}

fn is_consonant(c: char) -> bool {
    ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'].contains(&c)
}

Does my code satisfy whatever is required for it to be idiomatic Rust?

\$\endgroup\$
3
  • \$\begingroup\$ Can you provide the problem statement? It's easier to review code when having it available. \$\endgroup\$
    – lukstru
    Jul 22, 2022 at 11:03
  • 1
    \$\begingroup\$ I don't believe you have satisfied the requirements of the exercise, since it says that you have to transform each word, and you have no word-splitting code in your implementation. \$\endgroup\$ Jul 22, 2022 at 16:33
  • 3
    \$\begingroup\$ is_consonant() has a very misleading name - that sort of thing will certainly trip you up one day. \$\endgroup\$ Jul 23, 2022 at 13:15

1 Answer 1

2
\$\begingroup\$

Suggested improvements:

Use trim() to remove the newline and other white spaces.

let mut inp = inp.trim().to_string();

The function is_consonant() actually checks if a letter is a vowel so it should be renamed.


The vowels can be extracted into a const.

const VOWELS: [char; 10] = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'];

The is_vowel(c: char) function can take reference to a char since that it what it uses.

fn is_vowel(c: &char) -> bool {
    VOWELS.contains(c)
}

Final Code:

use std::io;

const VOWELS: [char; 10] = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'];

fn main() {
    let mut inp = String::new();
    io::stdin().read_line(&mut inp).expect("Could not read");
    let mut inp = inp.trim().to_string();

    let cha = inp.chars().next().expect("Empty string");

    if is_vowel(&cha) {
        inp += "-hay";
    } else {
        inp.remove(0);
        inp += &format!("-{}ay", cha);
    }

    println!("{}", inp);
}

fn is_vowel(c: &char) -> bool {
    VOWELS.contains(c)
}


Additional changes:

It is possible to avoid some String allocations but doing so makes the code a bit more unreadable (in my opinion). Nonetheless I feel like it is worth at least mentioning them.


Replace format! by pushing to the original string to avoid a String allocation.

inp.remove(0);
inp += &format!("-{}ay", cha);

Can be replaced with:

inp.remove(0);
inp.push('-');
inp.push(cha);
inp.push_str("ay");

Avoid cloning the input String after trimming the whitespaces.

let mut inp = inp.trim().to_string();

Can be replaced with:

inp.truncate(inp.trim().len());

Convert the first character to lower case before checking if it is a vowel.

let cha = inp.chars().next().expect("Empty string");

Can be replaced with:

let cha = inp.chars().next().expect("Empty string").to_lowercase().next().unwrap();
\$\endgroup\$

Your Answer

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

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