![](/img/trans.png)
[英]Rust: error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements in closure
[英]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.