我正在尝试将字段放在应该包含Option<closure>
的结构上。
然而,Rust正在向我大吼大叫,我必须指明它的生命周期(并不是说我真的会这么说)。我正尽力做到这一点,但Rust对我提出的建议并不满意。看看我对我得到的编译错误的内联注释。
struct Floor{
handler: Option<|| ->&str> //this gives: missing lifetime specifier
//handler: Option<||: 'a> // this gives: use of undeclared lifetime name `'a`
}
impl Floor {
// I guess I need to specify life time here as well
// but I can't figure out for the life of me what's the correct syntax
fn get(&mut self, handler: || -> &str){
self.handler = Some(handler);
}
}
答案 0 :(得分:15)
这有点棘手。
作为一般经验法则,只要您在数据结构中存储借用的引用(即&
类型),就需要命名其生命周期。在这种情况下,您使用'a
走在正确的轨道上,但必须在当前范围中引入'a
。它与引入类型变量的方式相同。所以要定义你的Floor
结构:
struct Floor<'a> {
handler: Option<|| -> &'a str>
}
但这里还有另一个问题。闭包本身也是一个具有生命周期的引用,也必须命名。所以这里有两种不同的生命周期!试试这个:
struct Floor<'cl, 'a> {
handler: Option<||:'cl -> &'a str>
}
对于您的impl Floor
,您还需要将这些生命周期介绍到范围内:
impl<'cl, 'a> Floor<'cl, 'a> {
fn get(&mut self, handler: ||:'cl -> &'a str){
self.handler = Some(handler);
}
}
你可以在技术上将其减少到一个生命周期并使用||:'a -> &'a str
,但这意味着返回的&str
始终与闭包本身具有相同的生命周期,我认为这是一个不好的假设
答案 1 :(得分:3)
回答当前Rust版本1.x
:
有两种可能性来获得你想要的东西:无盒装封口或盒装封口。未装箱的闭包非常快(大多数情况下,它们都是内联的),但它们为结构添加了一个类型参数。盒装封闭在这里增加了一点自由:它们的类型被一个间接级别擦除,遗憾的是它有点慢。
我的代码有一些示例函数,因此它有点长,请原谅;)
完整代码:
struct Floor<F>
where F: for<'a> FnMut() -> &'a str
{
handler: Option<F>,
}
impl<F> Floor<F>
where F: for<'a> FnMut() -> &'a str
{
pub fn with_handler(handler: F) -> Self {
Floor {
handler: Some(handler),
}
}
pub fn empty() -> Self {
Floor {
handler: None,
}
}
pub fn set_handler(&mut self, handler: F) {
self.handler = Some(handler);
}
pub fn do_it(&mut self) {
if let Some(ref mut h) = self.handler {
println!("Output: {}", h());
}
}
}
fn main() {
let mut a = Floor::with_handler(|| "hi");
a.do_it();
let mut b = Floor::empty();
b.set_handler(|| "cheesecake");
b.do_it();
}
现在这有一些典型的问题:你不能简单地拥有Vec
多个Floor
,并且使用Floor
对象的每个函数都需要有类型参数& #39;自己的。另外:如果删除行b.set_handler(|| "cheesecake");
,代码将无法编译,因为编译器缺少b
的类型信息。
在某些情况下,您不会遇到这些问题 - 在其他情况下,您需要另外解决方案。
完整代码:
type HandlerFun = Box<for<'a> FnMut() -> &'a str>;
struct Floor {
handler: Option<HandlerFun>,
}
impl Floor {
pub fn with_handler(handler: HandlerFun) -> Self {
Floor {
handler: Some(handler),
}
}
pub fn empty() -> Self {
Floor {
handler: None,
}
}
pub fn set_handler(&mut self, handler: HandlerFun) {
self.handler = Some(handler);
}
pub fn do_it(&mut self) {
if let Some(ref mut h) = self.handler {
println!("Output: {}", h());
}
}
}
fn main() {
let mut a = Floor::with_handler(Box::new(|| "hi"));
a.do_it();
let mut b = Floor::empty();
b.set_handler(Box::new(|| "cheesecake"));
b.do_it();
}
它有点慢,因为我们为每个闭包都有一个堆分配,当调用盒装闭包时,它大部分时间是间接调用(CPU不喜欢间接调用.. )。
但Floor
结构没有类型参数,因此您可以拥有Vec
个结构。您也可以删除b.set_handler(Box::new(|| "cheesecake"));
,它仍然可以使用。