这里没有任何关于闭包的具体内容;它相当于:
fn main() {
let string = String::from("a:b:c");
let substrings = vec![&string[0..1], &string[2..3], &string[4..5]];
let string = string;
}
您正在尝试move the String
同时还有未偿还的借款。在我的例子中,它是另一个变量;在您的示例中,它是闭包的环境。不管怎样,你仍然在移动它。
此外,您尝试将子字符串移动到与所属字符串相同的闭包环境中。这使得整个问题等同于为什么我不能在同一结构中存储值和对该值的引用?:
struct Environment<'a> {
string: String,
substrings: Vec<&'a str>,
}
fn thing<'a>() -> Environment<'a> {
let string = String::from("a:b:c");
let substrings = vec![&string[0..1], &string[2..3], &string[4..5]];
Environment {
string: string,
substrings: substrings,
}
}
该对象是在环境中创建的,并且其范围仅限于该环境
我不同意;string
and substrings
被创建outside关闭的环境和搬进了它。正是这个举动让你绊倒。
一旦创建,它就可以安全地移至闭包。
In this情况确实如此,但只是因为你,程序员,可以保证字符串数据的地址inside the String
将保持不变。您知道这一点有两个原因:
-
String
是通过堆分配在内部实现的,因此移动String
不移动字符串数据。
- The
String
永远不会被改变,这可能会导致字符串重新分配,从而使任何引用无效。
The easiest您的示例的解决方案是将切片简单地转换为String
s 并让闭包完全拥有它们。如果这意味着您可以释放一个大字符串以支持一些较小的字符串,那么这甚至可能是一个净收益。
否则,您符合“存在生命周期跟踪过于热心的特殊情况”中规定的标准为什么我不能在同一结构中存储值和对该值的引用?,所以你可以使用像这样的板条箱:
拥有_参考
use owning_ref::RcRef; // 0.4.1
use std::rc::Rc;
fn stage_action() -> impl Fn() {
let string = RcRef::new(Rc::new(String::from("a:b:c")));
let substrings = vec![
string.clone().map(|s| &s[0..1]),
string.clone().map(|s| &s[2..3]),
string.clone().map(|s| &s[4..5]),
];
move || {
for sub in &substrings {
println!("{}", &**sub);
}
}
}
fn main() {
let action = stage_action();
action();
}
衔尾蛇
use ouroboros::self_referencing; // 0.2.3
fn stage_action() -> impl Fn() {
#[self_referencing]
struct Thing {
string: String,
#[borrows(string)]
substrings: Vec<&'this str>,
}
let thing = ThingBuilder {
string: String::from("a:b:c"),
substrings_builder: |s| vec![&s[0..1], &s[2..3], &s[4..5]],
}
.build();
move || {
thing.with_substrings(|substrings| {
for sub in substrings {
println!("{}", sub);
}
})
}
}
fn main() {
let action = stage_action();
action();
}
请注意,我不是这两个箱子的专家用户,因此这些示例可能不是best使用它。