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?
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With