如何修改在循环中使用自身的 Cow 变量?
How to modify a Cow variable that uses itself in a loop?
我正在尝试删除字符串中的所有括号。没有考虑太难,我只是做了一个简单的正则表达式替换(即问题不是特别是关于摆脱任意级别的嵌套括号,但如果你愿意,请随时在评论中提出更好的方法).
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = "Text (with some (nested) parentheses)!";
let re = Regex::new(r"\([^()]*\)")?;
let output = re.replace_all(&input, "");
let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// ...
assert_eq!("Text !", output);
println!("Works!");
Ok(())
}
因为我不知道括号是如何嵌套的,所以我需要循环替换而不是重复它"just enough times"。但是,创建一个循环会创建一个新的范围,这就是我在与借用检查器的讨论中遇到的死点。
显示我在循环中尝试做的事情的最简单的情况是:
let mut output = re.replace_all(&input, "");
while re.is_match(&output) {
output = re.replace_all(&output, "");
}
但是这无法完成,因为我正在分配给借用的变量:
error[E0506]: cannot assign to `output` because it is borrowed
--> src/main.rs:9:9
|
9 | output = re.replace_all(&output, "");
| ^^^^^^ ------- borrow of `output` occurs here
| |
| assignment to borrowed `output` occurs here
| borrow later used here
理想情况下,我想做的是创建具有相同名称的新变量绑定,但使用 let output =
会影响外部变量绑定,因此循环将无限循环。
无论我创建什么内部或外部临时变量,我都不能让它做我想做的事。我还尝试使用 re.replace_all()
returns Cow
这一事实,并尝试在几个地方使用 .to_owned()
和 .to_string()
,但这也无济于事。
这里是 link to a playground。
re.replace_all()
returns Cow
这就是问题的根源。编译器知道 return 值可能引用 output
,但它也会 替换 output
,导致 output
被删除离开。如果它允许这样做,引用将指向未分配的内存,导致内存不安全。
解决办法是完全避免借用。
tried using .to_owned()
to_owned
Cow
只是 return 相同 Cow
。也许你的意思是 into_owned
?
let mut output = re.replace_all(&input, "").into_owned();
while re.is_match(&output) {
output = re.replace_all(&output, "").into_owned();
}
and .to_string()
in a couple of places
这也有效:
let mut output = re.replace_all(&input, "").to_string();
while re.is_match(&output) {
output = re.replace_all(&output, "").to_string();
}
Shepmaster 的答案有效,但效率不高。 Cow
类型的一个微妙 属性 是通过检查它,我们可以确定字符串是否被修改,如果没有则跳过工作。
由于 Rust 类型系统的限制,如果值 未修改 则 Cow::into_owned()
进行复制。 ( 修改后的 值的 Cow::into_owned()
不会复制)。 (into_owned documentation)
在您的用例中,我们可以检测未修改的 Cow
-- Cow::Borrowed
-- 并跳过 into_owned()
.
let mut output = /* mutable String */;
while re.is_match(&output).unwrap() {
match re.replace_all(&output, "") {
// Unmodified -- skip copy
Cow::Borrowed(_) => {}
// replace_all() returned a new value that we already own
Cow::Owned(new) => output = new,
}
}
但我们可以更进一步。同时调用 is_match()
和 replace_all()
意味着模式匹配了两次。凭借我们对 Cow
s 的新知识,我们可以优化它:
let mut output = /* mutable String */;
// Cow::Owned is returned when the string was modified.
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = new;
}
编辑:如果您的输入值是不可变的,您也可以通过将其设为 Cow
来避免 .to_string()
复制:
let input = "value";
let mut output = Cow::from(input);
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = Cow::Owned(new);
}
我正在尝试删除字符串中的所有括号。没有考虑太难,我只是做了一个简单的正则表达式替换(即问题不是特别是关于摆脱任意级别的嵌套括号,但如果你愿意,请随时在评论中提出更好的方法).
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = "Text (with some (nested) parentheses)!";
let re = Regex::new(r"\([^()]*\)")?;
let output = re.replace_all(&input, "");
let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// ...
assert_eq!("Text !", output);
println!("Works!");
Ok(())
}
因为我不知道括号是如何嵌套的,所以我需要循环替换而不是重复它"just enough times"。但是,创建一个循环会创建一个新的范围,这就是我在与借用检查器的讨论中遇到的死点。
显示我在循环中尝试做的事情的最简单的情况是:
let mut output = re.replace_all(&input, "");
while re.is_match(&output) {
output = re.replace_all(&output, "");
}
但是这无法完成,因为我正在分配给借用的变量:
error[E0506]: cannot assign to `output` because it is borrowed
--> src/main.rs:9:9
|
9 | output = re.replace_all(&output, "");
| ^^^^^^ ------- borrow of `output` occurs here
| |
| assignment to borrowed `output` occurs here
| borrow later used here
理想情况下,我想做的是创建具有相同名称的新变量绑定,但使用 let output =
会影响外部变量绑定,因此循环将无限循环。
无论我创建什么内部或外部临时变量,我都不能让它做我想做的事。我还尝试使用 re.replace_all()
returns Cow
这一事实,并尝试在几个地方使用 .to_owned()
和 .to_string()
,但这也无济于事。
这里是 link to a playground。
re.replace_all()
returnsCow
这就是问题的根源。编译器知道 return 值可能引用 output
,但它也会 替换 output
,导致 output
被删除离开。如果它允许这样做,引用将指向未分配的内存,导致内存不安全。
解决办法是完全避免借用。
tried using
.to_owned()
to_owned
Cow
只是 return 相同 Cow
。也许你的意思是 into_owned
?
let mut output = re.replace_all(&input, "").into_owned();
while re.is_match(&output) {
output = re.replace_all(&output, "").into_owned();
}
and
.to_string()
in a couple of places
这也有效:
let mut output = re.replace_all(&input, "").to_string();
while re.is_match(&output) {
output = re.replace_all(&output, "").to_string();
}
Shepmaster 的答案有效,但效率不高。 Cow
类型的一个微妙 属性 是通过检查它,我们可以确定字符串是否被修改,如果没有则跳过工作。
由于 Rust 类型系统的限制,如果值 未修改 则 Cow::into_owned()
进行复制。 ( 修改后的 值的 Cow::into_owned()
不会复制)。 (into_owned documentation)
在您的用例中,我们可以检测未修改的 Cow
-- Cow::Borrowed
-- 并跳过 into_owned()
.
let mut output = /* mutable String */;
while re.is_match(&output).unwrap() {
match re.replace_all(&output, "") {
// Unmodified -- skip copy
Cow::Borrowed(_) => {}
// replace_all() returned a new value that we already own
Cow::Owned(new) => output = new,
}
}
但我们可以更进一步。同时调用 is_match()
和 replace_all()
意味着模式匹配了两次。凭借我们对 Cow
s 的新知识,我们可以优化它:
let mut output = /* mutable String */;
// Cow::Owned is returned when the string was modified.
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = new;
}
编辑:如果您的输入值是不可变的,您也可以通过将其设为 Cow
来避免 .to_string()
复制:
let input = "value";
let mut output = Cow::from(input);
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = Cow::Owned(new);
}