Search code examples
stringrustany

Check if string begins with any of certain characters


I want to check if a string begins with a vowel. While I could iterate over a list of vowels and check each individually like so:

let s = String::from("apple");

let vowels = ['a', 'e', 'i', 'o', 'u'];

for v in vowels {
    if s.starts_with(v) {
        println!("{} starts with a vowel.", s);
        break;
    }
}

I'd prefer a better / more concise way. Here is what I tried:

if vowels.iter().any(|v| s.starts_with(v)) {
    println!("{} begins with a vowel.", s);
}

This gives the following error(s):

error[E0277]: expected a `Fn<(char,)>` closure, found `char`
    --> src/exercises.rs:61:44
     |
61   |     if vowels.iter().any(|v| s.starts_with(v)) {
     |                                ----------- ^ expected an `Fn<(char,)>` closure, found `char`
     |                                |
     |                                required by a bound introduced by this call
     |
     = help: the trait `Fn<(char,)>` is not implemented for `char`
     = note: required because of the requirements on the impl of `FnOnce<(char,)>` for `&char`
     = note: required because of the requirements on the impl of `Pattern<'_>` for `&char`
note: required by a bound in `core::str::<impl str>::starts_with`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `ch8_common_collections` due to previous error

I'm not sure how to do this. I just want to determine if the string begins with a vowel. Yes, I know this is an English/ASCII-centric solution (I'm a beginner).


Solution

  • That isn't a great error message, but you just need to take a reference in your closure:

    fn main() {
        let s = String::from("apple");
        let vowels = ['a', 'e', 'i', 'o', 'u'];
    
        if vowels.iter().any(|&v| s.starts_with(v)) {
            //                ^
            println!("{} begins with a vowel.", s);
        }
    }
    

    or deref v:

    fn main() {
        let s = String::from("apple");
        let vowels = ['a', 'e', 'i', 'o', 'u'];
    
        if vowels.iter().any(|v| s.starts_with(*v)) {
            //                                 ^
            println!("{} begins with a vowel.", s);
        }
    }
    

    The reason for that is because iter yields references to its next element, so you either need to dereference the reference, or expect it in the first place.