How to fix parameter: recursive call or mutable or something else?

I have a function that accepts a URL of a web site. (no path) I'd like to be flexible in accepting a trailing slash or not. In the function I'd want the URL without the trailing slash.
I came up with three solutions.

In the 1st case I make the parameter mutable and change it in the function. This is probably the one I'd use in Python.

In the 2nd case I recursively call the processing function with the fixed url.
In the 3rd case there are two functions, the real code is in the process(). The pre_processor only call the process with the right argument.

Which one would you recommend? Something totally different?

fn main() {
    for url in [
        "https://rust.code-maven.com".to_string(),
        "https://rust.code-maven.com/".to_string(),
    ] {
        process_mut(&url);
        process_rec(&url);
        pre_process(&url);
    }
}

fn process_rec(url: &str) {
    if url.ends_with('/') {
        return process_rec(&url[0..url.len() - 1]);
    }
    println!("Process '{}'", url);
}

fn process_mut(mut url: &str) {
    if url.ends_with('/') {
        url = &url[0..url.len() - 1];
    }
    println!("Process '{}'", url);
}

fn pre_process(url: &str) {
    if url.ends_with('/') {
        return process(&url[0..url.len() - 1]);
    }
    process(url)
}
fn process(url: &str) {
    println!("Process '{}'", url);
}

Well pre_process and process_mut are basically the same thing. I guess you would further use them something like this

let mut url = "https://rust.code-maven.com/";
url = pre_process(url);
process(url);

/// or
let url = "https://rust.code-maven.com/";
process_mut(url);

If you need a named function do pre_process. If not, then just use process_mut.
The recursive solution offers no benefit in my mind. The problem doesn't feel inherently recursive to me so it is just a roadblock where you have to stop and think about it. Also, it may cost you an extra function call.

Btw, the name process_mut is missleading. Only the parameter binding is mutable but not the actual string slice. So no mutation of the passed data can happen. Also, one of the parameter variables beeing mut is an implementation detail. It's the same as

process_mut(url: &str) {
    let mut url = url;
    // more stuff
}

You can see that the mutability of the binding (not the data behind it) is not part of the function signature and thus an implementation detail.

1 Like

All of these seem to be overly complicated. Since you are accepting a raw &str as the URL, why don't you just call url.trim_end_matches('/')? This would work whether or not the string has a trailing slash, and requires no modification in place nor recursion.

3 Likes

Because I did not think about it :slight_smile:
Thanks.

The solution with trim_end_matches is a nice one for the generic case. For the specific case of URL handling I ended up using the url crate, I just changed the variable name to site to reduce confusion with the name of the crate:

url::Url::parse(&site).unwrap()
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.