rustpattern-matching

Avoid constructing string just to match


I just wrote this, which feels ugly in a low level language:

    match std::env::var("IN_DEPLOYMENT")
        .unwrap_or("false".to_string())
        .as_str()
    {
        "false" | "FALSE" | "0" => {
            tracing_subscriber::fmt().init();
        }
        _ => tracing_subscriber::fmt().json().init(),
    }

How do I avoid needing the temporary string? My first thought was to match directly on the result, but I couldn't work out how to tranform Result<String,_> into Result<&str, _>.


Solution

  • You should firstly convert Result<String, E> to Result<&str, &E>. This can be done with Result::as_deref method:

    fn foo() {
        match std::env::var("IN_DEPLOYMENT").as_deref().unwrap_or("false") {
            "false" | "FALSE" | "0" => todo!(),
            _ => todo!(),
        }
    }
    

    On the other note if you would really need an owned String, prefer Result::unwrap_or_else over Result::unwrap_or (same argument goes for Option), because this will prevent allocation when there is data to unwrap. There is clippy lint that checks for it.