High performance recursion

Task:
Expand "${HOME}/dir1/${DIR2}/dir3" to a string which does not contain any "${}".

Here is my solution,it return a String everytime which maybe inefficient.
So, Can you come up with a better one?

use std::env;

fn env_finder(name:&str)->Option<String>{
    if let Some(v) =  env::var_os(name) {
        return Some(env_recur(v.to_str().unwrap()));
    }else{
        return None;
    }
} 
//expand ${HOME}/dir1/${DIR2}/dir3
fn env_recur(path:&str)-> String{
    //cur_recur +=1;
    //if cur_recur > MAX_RECUR{return;}
    let mut s=path.splitn(2,"${");
    let head=s.next();
    let mut re = head.unwrap().to_owned();
    //re.push_str(head.unwrap());
    let tail=s.next();
    match tail {
        Some(t) => {
            let mut s2=t.splitn(2,"}");
            let name=s2.next().unwrap();
            let tail2=s2.next();
            match tail2{
                Some(t2) => {
                    if let Some(val) = env::var_os(name){
                        re.push_str(&env_recur(val.to_str().unwrap()));
                    }
                    if t2 != ""{
                        re.push_str(&env_recur(t2));
                }
                },
                None => {}
            }
        },
        None => {} 
    }
    return re;
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        env::set_var("A","dir1/${B}/dir3");
        env::set_var("B","dir4/${C}/${C}");
        env::set_var("C","dir5");
        assert_eq!(env_finder("A"),Some("dir1/dir4/dir5/dir5/dir3".to_owned()));
    }
}

You can change the env_recur signature to take an additional buf: &mut String (instead of returning String), and just push to it. That way, you'll create the string just once, in the env_finder. As a bonus, the resulting function will be tail-recursive!

1 Like