试图保存关闭的参考,但活得不够长

  • 本文关键字:不够 参考 保存 rust
  • 更新时间 :
  • 英文 :


我对铁锈还很陌生,我正在与终身的东西rn作斗争。所以基本上我在构造一个结构,我想在这个结构中存储一个闭包。但其中一个被捕获的变量的寿命不够长。

struct HtmlOut<'a> {
echo_escaped: &'a dyn Fn(&String)
}
// not really implemented yet
fn escape(s: &String) -> &String {
return s;
}
impl<'a> HtmlOut<'a> {

fn new(echo: &'a dyn Fn(&String)) -> HtmlOut<'a> {
let echo_element_escaped_cls = |s: &String| { echo(escape(s)) };
let echo_element_escaped: &'a dyn Fn(&String) = &echo_element_escaped_cls;
return HtmlOut {
echo_escaped: echo_element_escaped
}
}
}

我有两个错误:

|s: &String| { echo(escape(s)) };
------------   ^^^^ borrowed value does not live long enough

&'a dyn Fn(&String) = &echo_element_escaped_cls;
-------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
|
type annotation requires that `echo_element_escaped_cls` is borrowed for `'a`

我的问题是:

  • 当所有内容都用相同的生存期说明符'a进行注释时,为什么echo的生存期不够长
  • 如何重写此代码,使echo的寿命足够长

您的代码不能像编写的那样工作,因为引用必须引用某些东西。Rust没有GC,所以不能只在函数中创建一个值,创建对它的引用,然后从函数返回引用。您需要拥有值,这可以通过将值存储在结构中来实现,或者在dyn Trait特征对象的情况下,通过装箱来实现:

struct HtmlOut {
echo_escaped: Box<dyn Fn(&str)>,
}

(我还修改了签名以接受&str而不是&String,后者更灵活,工作效果也很好,详细信息请参阅此处。(

另一个问题是escape函数——要转义字符串,它必须能够创建转义字符串,而不仅仅是返回对其他人创建的字符串的引用。它需要接受&mut String来修改字符串,或者返回一个拥有的String:

// not really implemented yet
fn escape(s: &str) -> String {
s.to_string()
}

最后,构造函数需要接受echo作为一个拥有的值,这样它就可以移动到闭包中:

impl HtmlOut {
fn new(echo: Box<dyn Fn(&str)>) -> HtmlOut {
let echo_element_escaped_cls = move |s: &str| echo(&escape(s));
let echo_element_escaped = Box::new(echo_element_escaped_cls);
return HtmlOut {
echo_escaped: echo_element_escaped,
};
}
}

为了获得最大的灵活性,构造函数甚至可以接受任意闭包,并将装箱作为自己的实现细节:

fn new<F: Fn(&str) + 'static>(echo: F) -> HtmlOut {
let echo = Box::new(echo);
let echo_element_escaped_cls = move |s: &str| echo(&escape(s));
let echo_element_escaped = Box::new(echo_element_escaped_cls);
return HtmlOut {
echo_escaped: echo_element_escaped,
};
}

游乐场

最新更新