Make validation in Rust simple

I have input with 2 variables (x and y). I need to check that they are not Null and both of them don’t contain "?". I achieved it with my code, but for me it seems not super optimized. Is it possible (for sure it is, but I don’t know how) to improve it?

#[derive(Debug)]
pub enum TestError {
    ContainsQuestionMark,
}

pub type TestResult = Result<bool, TestError>;

fn main() {
    let x = Some(String::from("x"));
    let y = Some(String::from("y"));

    if x.is_some() && y.is_some() {
        let x = x.clone().unwrap();
        let y = y.clone().unwrap();
        if validate(&x, &y).is_ok() {
            out(&x, &y);
        }
    } else {
        println!("x and y are Null");
    }
}

fn validate(x: &String, y: &String) -> TestResult {
    if x.contains("?") || y.contains("?") {
        println!("x or y contains ?");
        return Err(TestError::ContainsQuestionMark);
    }
    Ok(true)
}

fn out(x: &String, y: &String) {
    println!("These are x = {x}, y = {y}");
    std::process::exit(0);
}

>Solution :

You can use if-let to both check and unwrap options at the same time.

if let Some(x) = &x {
    if let Some(y) = &y {
        if validate(x, y).is_ok() {
            out(x, y);
        }
    }
} else {
    println!("x or y is None");
}

You could then get fancy and match both at the same time by stuffing &x and &y into a tuple.

if let (Some(x), Some(y)) = (&x, &y) {
    if validate(x, y).is_ok() {
        out(x, y);
    }
} else {
    println!("x or y is None");
}

Playground


By the way, it’s better to take function parameters as &str rather than &String. A &str can accept not just String references, but also static strings and string slices that aren’t stored in mutable String buffers. A &String reference automatically converts into &str so there’s no ergonomic cost.

fn validate(x: &str, y: &str) -> TestResult {
    ...
}

fn out(x: &str, y: &str) {
    ...
}

Leave a Reply