我正在尝试实现以下代码,该代码会从Cow<str>
的切片中删除前缀。
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(),
}
}
}
我有两个问题:
我无法将其编译 - 我尝试了&
和*
的大量组合,但无济于事。
是否有更好的方法将函数应用于Cow<str>
,而不必每次都match
Borrowed
和Owned
。我的意思是,似乎我应该能够执行类似*t = t.trim_left_matches(prefix)
的操作,如果t
是Borrowed(str)
,则会将其保留为str
(因为trim_left_matches
允许),如果它是Owned(String)
,则将其保留为String
。同样地,对于replace()
,它会意识到必须将两者都转换为String
(因为您无法在replace()
上使用str
)。是这样的吗?
答案 0 :(得分:4)
问题#1强烈暗示你如何认为Rust中的模式匹配和/或指针工作与它们的实际工作方式并不完全一致。以下代码编译:
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(),
}
}
}
如果您的案例Borrowed(&s)
与Borrowed(&str)
匹配,则s
的类型为str
。这是不可能的:你绝对不能拥有动态大小类型的变量。这也适得其反。鉴于您希望修改 s
,按值绑定它将无济于事。
您想要的是修改Borrowed
变体中包含的内容。这意味着您需要一个指向该存储位置的可变指针。因此,Borrowed(ref mut s)
:这不根本不会对Borrowed
内的值进行解构。相反,它直接绑定到&str
,意味着s
属于&mut &str
类型;指向a(指向str
的指针)的可变指针。换句话说:一个指向字符串切片的可变指针。
此时,通过可变指针重新分配值来完成Borrowed
的内容变更:*s = ...
。
最后,完全相同的推理适用于Owned
情况:你试图绑定按值,然后改变它,这不可能做你想要的。而是通过可变指针绑定到存储位置,然后重新分配它。
关于问题#2 ......不是真的。这意味着某种重载,Rust没有做(通过慎重选择)。如果你正在做很多,你可以编写一个扩展特征,将{4}感兴趣的方法添加到其中。
答案 1 :(得分:3)
你绝对可以做到。
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
表示“对值进行可变引用,并在模式中将其称为s
”。因此,您s
类型为&mut &str
或&mut String
。然后,您必须使用*s =
来更改可变引用指向的内容(因此,更改Cow
内的字符串)。