Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return original or modified str

Tags:

rust

I have a function to clean a string that looks something like this:

fn clean(s: &str) -> &str { // but not sure about return type
    if /* needs cleaning */ {
        let cleaned: String = s.chars().filter( /* etc */ ).collect();
        cleaned
    } else {
        s
    }
}

Except this doesn't work as written, because cleaned is String, not a &str.

The goal here is to only perform an allocation if necessary - if the string needs to be modified, I want to replace it with a new one, and if it doesn't, I don't want to call to_string() on it. Ideally, I'd like that to be transparent to the caller, but it doesn't have to be - I have control of the calling code too. Even so, I haven't found a workaround, because if the newly-created String, or even a borrow of it, ends up in some kind of if or else block in the caller, it's lifetime isn't long enough to use in the contexts where the original string is used otherwise. For example, this also doesn't work:

fn caller(s: &str) {
    if needs_cleaning(s) {
        let cleaned = clean(s); // where clean always returns a new String
        s = &cleaned;
    }

    / * do stuff with the clean string */
}

What's the right approach here?

like image 928
David Avatar asked Oct 29 '15 16:10

David


1 Answers

You're looking for Cow:

use std::borrow::Cow;

fn clean(s: &str) -> Cow<str> {
    if /* needs cleaning */ {
        let cleaned: String = s.chars().filter(/* etc */).collect();
        Cow::Owned(cleaned)
    } else {
        Cow::Borrowed(s)
    }
}
like image 95
Steven Avatar answered Oct 23 '22 16:10

Steven