I'm trying to implement the following code, which removes the prefix from a slice of Cow<str>
's.
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
for t in v.iter_mut() {
match *t {
Borrowed(&s) => s = s.trim_left_matches(prefix),
Owned(s) => s = s.trim_left_matches(prefix).to_string(),
}
}
}
I have two questions:
I can't get this to compile - I've tried loads of combinations of &
's and *
's but to no avail.
Is there a better way to apply functions to a Cow<str>
without having to match
it to Borrowed
and Owned
every time. I mean it seems like I should just be able to do something like *t = t.trim_left_matches(prefix)
and if t
is a Borrowed(str)
it leaves it as a str
(since trim_left_matches
allows that), and if it is an Owned(String)
it leaves it as a String
. Similarly for replace()
it would realise it has to convert both to a String
(since you can't use replace()
on a str
). Is something like that possible?
Question #1 strongly implies how you think pattern matching and/or pointers work in Rust doesn't quite line up with how they actually work. The following code compiles:
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
use std::borrow::Cow::*;
for t in v.iter_mut() {
match *t {
Borrowed(ref mut s) => *s = s.trim_left_matches(prefix),
Owned(ref mut s) => *s = s.trim_left_matches(prefix).to_string(),
}
}
}
If your case, Borrowed(&s)
is matched against Borrowed(&str)
, meaning that s
is of type str
. This is impossible: you absolutely cannot have a variable of a dynamically sized type. It's also counter-productive. Given that you want to modify s
, binding to it by value won't help at all.
What you want is to modify the thing contained in the Borrowed
variant. This means you want a mutable pointer to that storage location. Hence, Borrowed(ref mut s)
: this is not destructuring the value inside the Borrowed
at all. Rather, it binds directly to the &str
, meaning that s
is of type &mut &str
; a mutable pointer to a (pointer to a str
). In other words: a mutable pointer to a string slice.
At that point, mutating the contents of the Borrowed
is done by re-assigning the value through the mutable pointer: *s = ...
.
Finally, the exact same reasoning applies to the Owned
case: you were trying to bind by-value, then mutate it, which cannot possibly do what you want. Instead, bind by mutable pointer to the storage location, then re-assign it.
As for question #2... not really. That would imply some kind of overloading, which Rust doesn't do (by deliberate choice). If you are doing this a lot , you could write an extension trait that adds methods of interest to Cow
.
You can definitely do it.
fn remove_prefix(v: &mut [Cow<str>], prefix: &str) {
for t in v.iter_mut() {
match *t {
Cow::Borrowed(ref mut s) => *s = s.trim_left_matches(prefix),
Cow::Owned(ref mut s) => *s = s.trim_left_matches(prefix).to_string(),
}
}
}
ref mut s
means “take a mutable reference to the value and call it s
” in a pattern. Thus you have s
of type &mut &str
or &mut String
. You must then use *s =
in order to change what that mutable reference is pointing to (thus, change the string inside the Cow
).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.