如何解决导致错误的闭包[E0495]:无法推断适当的生存期



我有这个"简化"的代码来演示我在更复杂的项目中遇到的问题。

我创建了一个闭包来捕获一些参数,这样我就可以在两个地方调用一个小函数,而无需重复代码。 不幸的是,现在涉及生命周期,我很难理解编译器到底是什么感到困惑:

use std::io::Write;
pub struct X<'c>
{
maybe_file: Option<Box<dyn Write+'c>>,
}
impl<'c> X<'c>
{
pub fn wrap<'a:'c,'b:'c> (prefix:&'a str, base: &'b mut X<'b>) ->X<'c>
{
return X::<'c> {
maybe_file: Some(Box::new(X::wrapper(prefix, base))),
}
}
pub fn wrapper<'a, 'b>(prefix:&'a str, base:&'b mut X<'b>) -> Wrapper<'a,'b>
{
Wrapper {
prefix:prefix, base:base
}
}
pub fn boop_the_snoot(&self) {}
}
//
pub struct Wrapper<'a,'b>
{
pub prefix: &'a str,
pub base: &'b X<'b>,
}
impl<'a,'b> Write for Wrapper<'a,'b>
{
fn write(&mut self, buf:&[u8]) ->Result<usize, std::io::Error> { Ok(0) }
fn flush(&mut self) ->Result<(), std::io::Error> { Ok(()) }
}

pub fn bacon(x:&mut X, scale:f32)
{
}
pub fn eggs<'c>(x:&'c mut X<'c>, scale:f32)
{
bacon( & mut X::wrap("A:t", x), scale);
let f = |x:& mut X| {
bacon(& mut X::wrap("B:t", x), scale);
};
f(x);
f(x);
}

这给了我以下编译错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
--> /home/thoth/src/embroidery/filler/src/lifetimes_shenanigans.rs:68:19
|
68 |       bacon(& mut X::wrap("B:t", x), scale);
|                   ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 67:13...
--> /home/thoth/src/embroidery/filler/src/lifetimes_shenanigans.rs:67:13
|
67 |       let f = |x:&mut X| {
|  _____________^
68 | |       bacon(& mut X::wrap("B:t", x), scale);
69 | |     };
| |_____^
note: ...so that reference does not outlive borrowed content
--> /home/thoth/src/embroidery/filler/src/lifetimes_shenanigans.rs:68:35
|
68 |       bacon(& mut X::wrap("B:t", x), scale);
|                                   ^
note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the body at 67:13...
--> /home/thoth/src/embroidery/filler/src/lifetimes_shenanigans.rs:67:13
|
67 |       let f = |x:&mut X| {
|  _____________^
68 | |       bacon(& mut X::wrap("B:t", x), scale);
69 | |     };
| |_____^
= note: ...so that the expression is assignable:
expected &mut lifetimes_shenanigans::X<'_>
found &mut lifetimes_shenanigans::X<'_>

这种逻辑保护我免受什么样的终身犯罪? 我应该在此代码中添加什么以使 rust 编译器能够理解各种对象的生命周期?

我能够通过将形式&'b mut X<'b>的声明替换为&'z mut X<'b>来编译代码,基本上将引用的生存期与X中字段的生存期分离。

另一个重要的更改是从eggs()函数中删除所有生存期。 这实际上提出了自己的问题:是否有可能在 egg 函数中显式声明生命周期并仍然对其进行编译? 我做了一些笨拙的尝试,最终得到了[E0502]: cannot borrow*xas immutable because it is also borrowed as mutable,这证实了我还不明白的微妙之处。

补丁如下所示:

@@ -7,13 +7,13 @@
impl<'c> X<'c>
{
-    pub fn wrap<'a:'c,'b:'c> (prefix:&'a str, base: &'b mut X<'b>) ->X<'c>
+    pub fn wrap<'a:'c,'b:'c,'z:'c> (prefix:&'a str, base: &'z mut X<'b>) ->X<'c>
{
return X::<'c> {
maybe_file: Some(Box::new(X::wrapper(prefix, base))),
}
}
-    pub fn wrapper<'a, 'b>(prefix:&'a str, base:&'b mut X<'b>) -> Wrapper<'a,'b>
+    pub fn wrapper<'a, 'b, 'z>(prefix:&'a str, base:&'z mut X<'b>) -> Wrapper<'a,'b, 'z>
{
Wrapper {
prefix:prefix, base:base
@@ -25,13 +25,13 @@
//
-pub struct Wrapper<'a,'b>
+pub struct Wrapper<'a,'b, 'z>
{
pub prefix: &'a str,
-    pub base: &'b X<'b>,
+    pub base: &'z X<'b>,
}
-impl<'a,'b> Write for Wrapper<'a,'b>
+impl<'a,'b,'z> Write for Wrapper<'a,'b,'z>
{
fn write(&mut self, buf:&[u8]) ->Result<usize, std::io::Error> { Ok(0) }
fn flush(&mut self) ->Result<(), std::io::Error> { Ok(()) }
@@ -43,7 +43,7 @@
}
-pub fn eggs<'c>(x:&'c mut X<'c>, scale:f32)
+pub fn eggs(x:& mut X, scale:f32)
{
bacon( & mut X::wrap("A:t", x), scale);
@@ -53,5 +53,7 @@
f(x);
+    x.boop_the_snoot();
+
f(x);
}

完整的"固定"源代码是

use std::io::Write;
pub struct X<'c>
{
maybe_file: Option<Box<dyn Write+'c>>,
}
impl<'c> X<'c>
{
pub fn wrap<'a:'c,'b:'c,'z:'c> (prefix:&'a str, base: &'z mut X<'b>) ->X<'c>
{
return X::<'c> {
maybe_file: Some(Box::new(X::wrapper(prefix, base))),
}
}
pub fn wrapper<'a, 'b, 'z>(prefix:&'a str, base:&'z mut X<'b>) -> Wrapper<'a,'b, 'z>
{
Wrapper {
prefix:prefix, base:base
}
}
pub fn boop_the_snoot(&self) {}
}
//
pub struct Wrapper<'a,'b, 'z>
{
pub prefix: &'a str,
pub base: &'z X<'b>,
}
impl<'a,'b,'z> Write for Wrapper<'a,'b,'z>
{
fn write(&mut self, buf:&[u8]) ->Result<usize, std::io::Error> { Ok(0) }
fn flush(&mut self) ->Result<(), std::io::Error> { Ok(()) }
}

pub fn bacon(x:&mut X, scale:f32)
{
}
pub fn eggs(x:& mut X, scale:f32)
{
bacon( & mut X::wrap("A:t", x), scale);
let f = |x:&mut X| {
bacon(& mut X::wrap("B:t", x), scale);
};
f(x);
x.boop_the_snoot();
f(x);
}

所以,这基本上是一半的答案:代码编译,我可以使用此模式继续我的项目;但是,它依赖于 rust 编译器在编译 eggs(( 时进行一些生命周期推理。 如果我们要使用与编译器推断的内容匹配的生存期信息来注释 eggs((,代码会是什么样子? 答案是教育性的。

最新更新