我有这个“简化”的代码来演示我在一个更复杂的项目中遇到的问题。
我创建了一个闭包来捕获一些参数,这样我就可以在两个地方调用一个小函数,而无需重复代码。不幸的是,现在涉及到生命周期,我很难理解编译器到底混淆了什么:

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()函数中删除所有生命周期。这实际上提出了它自己的问题:是否可以在eggs函数中明确声明生命周期,然后仍然让它编译?我做了一些笨拙的尝试,最后得到了[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(),代码会是什么样子?答案是教育性的。

关于rust - 我如何解决导致错误的闭包[E0495]:无法推断适当的生存期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57912253/

10-10 17:02