It should work, no? I’m imagining fn(impl Into<Cow<'a, str>>) -> Cow<'a, str>
with matching lifetimes. It’s of course also a bit non-trivial to decide how the owned case should be handled in the first place. I imagine, the String
could possibly, maybe, potentially… or maybe not… be re-used for the output String
even if some replacing happens… though certainly at least in the no-changes-made case it could be retained as-is. (Such things would have to be documented ^^.)
A fn(impl Into<Cow<'a, str>>) -> Cow<'a, str>
(or equivalently, apart from the convenience, a fn(Cow<'a, str>) -> Cow<'a, str>
) function is a bit like two functions: one fn(&'a str) -> Cow<'a, str>
function plus one fn(String) -> Cow<'a, str>
function (though the latter has no input to borrow from, so commonly it would be like a fn(String) -> String
function, except maybe when &'static str
return values are an option for certain cases). Offering two such functions distinctly would allow callers to wrap them up into a single fn(Cow<'a, str>) -> Cow<'a, str>
function themselves; and if the only optimized case of the fn(String) -> String
one is to keep the String
untouched when no changes are being made, then by inspecting the result of the fn(String) -> Cow<'a, str>
function, a user can write their own fn(Cow<'a, str>) -> Cow<'a, str>
wrapper easily.
In fact, it looks like Regex::replace
only ever returns exactly the original &str
in the Cow::Borrowed
case, it might just as well be a fn(&str) -> Result<String, NoMatchesFound>
kind of function, leaving keeping around the &str
to the caller. Of course, the benefit of not doing that can be increased convenience for the user out of the box. But the more complex the type signature, the more possible smart things or optimizations (such as the above-mentioned idea that maybe replacing within a String
could happen in-place, using existing String
capacity if available) that users might (incorrectly) expect need to be rules out in the documentation.
This whole discussion also makes me wonder about – something I have never tried to think too deeply about before yet – what the “ideal” API for HashMap
would look like, where at the moment HashMap::entry
has the unfortunate API design of always requiring an owned key. And sometimes, say for a HashMap<String, T>
, you already have an owned String
you no longer need afterwards, anyways; but if you only have a &str
, unconditionally cloning the thing seems “wasteful”. I don’t know how closely or loosely related such an entry
API would be to the things discussed here, but it’s not entirely different, I believe.