繁体   English   中英

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

[英]How do I work around closures causing error[E0495]: cannot infer an appropriate lifetime

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

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

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 * x as immutable because it is also borrowed as mutable [E0502]: cannot borrow as 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编译器在编译egg()时进行一些生命周期推断。 如果我们用与编译器推断的匹配的生存期信息注释egg(),代码将是什么样? 答案将是教育性的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM