Help with functions and closure

the following piece of code works when validate_with is passed a closure, but fails to compile when I declare a function outside and use it instead

let mail: String = Input::new()
        .with_prompt("Enter email")
        .validate_with(|input: &String| -> Result<(), &str> {
            if input.contains('@') {
                Ok(())
            } else {
                Err("This is not a mail address")
            }
        })
        .interact()
        .unwrap();

This fails to compile

fn validator_fn(input: &String) -> Result<(), &str> {
    if input.contains('@') {
        Ok(())
    } else {
        Err("This is not a mail address")
    }
}


fn main() {
    let mail: String = Input::new()
        .with_prompt("Enter email")
        .validate_with(validator_fn)
        .interact()
        .unwrap();
}

I get the following error -
mismatched types
expected enum Result<_, &_>
found enum Result<_, &_>

I am fairly new to rust and would like to know where I am going wrong. Thank you for taking time to help.

What crate are you using in your snippet?

I am using dialoguer

It's a lifetime error.

This function

fn validator_fn(input: &String) -> Result<(), &str> {
    if input.contains('@') {
        Ok(())
    } else {
        Err("This is not a mail address")
    }
}

is interpreted as

fn validator_fn<'a>(input: &'a String) -> Result<(), &'a str> {
    if input.contains('@') {
        Ok(())
    } else {
        Err("This is not a mail address")
    }
}

because of the lifetime elision.

Which force the input and the output to have the same lifetime.

To solve this use the 'static lifetime

fn validator_fn(input: &String) -> Result<(), &'static str> {
    if input.contains('@') {
        Ok(())
    } else {
        Err("This is not a mail address")
    }
}
3 Likes

Lifetime elision is biting you here, because it believes the error string you are returning lives only as long as the reference you pass as an argument to your function and not for 'static. Making this explicit works:

fn validator_fn(input: &String) -> Result<(), &'static str> {
    if input.contains('@') {
        Ok(())
    } else {
        Err("This is not a mail address")
    }
}

(checking whether a string contains the character '@' is not good enough for validating whether the string is an email address or not)

2 Likes

Thanks guys, got my doubt clear

1 Like