Help about String concat


#1

Hey folks, I have such a python function:

def foo(url, prefix="http://google.com/?s="):
    if not url.startswith('http'):
        url = prefix + url
    print(url)

and I want to translate this function in Rust,this is what I have done:

fn foo(url:&str){
        let mut prefix="http://google.com/?s=";
        if !url.starts_with("http") {
            let mut prefix_url = prefix.clone();
            let url = prefix_url.push_str(url);
        }
        println!("{:?}",url);
}

But my Rust function could not produce the expected result, it seems it is a feature of String.
How could I get the correct result ?


#2

The push_str() mutates the string, it doesn’t create a new copy with the url appended. That means the push_str() doesn’t return anything useful, kinda like how some_list.append() doesn’t return anything (well… technically it returns None). The Rust equivalent of this is the empty tuple, ().

In the let url = ... line you aren’t actually updating the url parameter. Instead you’re creating a new variable (which just happens to be called url) which is only valid for the lifetime of the if block. It’s to do with how scopes work, you may want to google “shadowing”.

That means when you do let url = prefix_url.push_str(url); your new url variable contains (). Then when you leave the if block and do println!("{:?}", url) you’re printing the original url parameter.

Here’s a playground snippet which annotates what’s happening. And this is probably more what you were meaning to do.


#3

A solution that avoids unnecessary heap activity, possibly there are better solutions:

use std::borrow::Cow;

fn foo(url: &str) {
    let mut url: Cow<str> = url.into();
    if !url.starts_with("http") {
        url = ["http://google.com/?s=", &url].concat().into();
    }
    println!("{}", url);
}

#4

it makes sense, your explaination is super clear


#5

wow, it works. I check the api document and example about Cow , it says:

The type Cow is a smart pointer providing clone-on-write functionality: it can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required.

But I still think it is not easy understand this feature