在编写习惯使用Rust时,我偶然发现编译错误。我想了解为什么我会收到错误以及该怎么做:
无法推断泛型中的生命周期参数的适当生命周期 因需求冲突而输入
我一直在研究很多涉及类似错误的问题,但大多数似乎与循环依赖有关,我不认为这就是这里发生的事情。
这是我对MWE的尝试,仍然可以进一步减少:
Playground link(稍有不同的错误讯息)
pub struct InnerMut<T> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T> InnerMut<T> {
pub fn new(stored_fn: fn(&mut T, u32)) -> InnerMut<T> {
return InnerMut {
state: std::u32::MAX,
stored_fn,
};
}
pub fn mutate(&mut self, data: &mut T) {
(self.stored_fn)(data, self.state);
self.state -= 1;
}
}
pub struct StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
mutable_closure: F,
}
impl<F> StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
pub fn new(mutable_closure: F) -> StoreFnMut<F> {
StoreFnMut { mutable_closure }
}
fn run_closure_on_mutable_borrow(&mut self) {
let mut buf = vec![0; 100];
(self.mutable_closure)(&mut buf[..]);
}
}
fn foo(borrow: &mut &mut [u8], val: u32) {
borrow[0] = (val & 0xff) as u8;
}
fn main() {
let mut capturing_closure;
let mut store_fn_mut;
let mut inner_mut;
inner_mut = InnerMut::new(foo);
capturing_closure = move |mut borrow: &mut [u8]| {
inner_mut.mutate(&mut borrow);
};
store_fn_mut = StoreFnMut::new(capturing_closure);
store_fn_mut.run_closure_on_mutable_borrow();
}
使用Rust 1.24.1进行编译时,我得到了这个有用的外观但令人困惑的错误消息:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
--> src/main.rs:48:31
|
48 | inner_mut = InnerMut::new(foo);
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 49:25...
--> src/main.rs:49:25
|
49 | capturing_closure = move |mut borrow: &mut [u8]| {
| _________________________^
50 | | inner_mut.mutate(&mut borrow);
51 | | };
| |_____^
note: ...so that expression is assignable (expected &mut &mut [u8], found &mut &mut [u8])
--> src/main.rs:50:26
|
50 | inner_mut.mutate(&mut borrow);
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the block suffix following statement 2 at 46:5...
--> src/main.rs:46:5
|
46 | / let mut inner_mut;
47 | |
48 | | inner_mut = InnerMut::new(foo);
49 | | capturing_closure = move |mut borrow: &mut [u8]| {
... |
53 | | store_fn_mut.run_closure_on_mutable_borrow();
54 | | }
| |_^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:46:9
|
46 | let mut inner_mut;
| ^^^^^^^^^^^^^
答案 0 :(得分:1)
我无法想到&mut &mut _
的用例。
如果您将foo
更改为
fn foo(borrow: &mut [u8], val: u32);
然后你又得到了另一个错误:
error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
--> src/main.rs:46:25
|
46 | let mut inner_mut = InnerMut::new(foo);
| ^^^^^^^^^^^^^ `[u8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
note: required by `<InnerMut<T>>::new`
嗯,此代码中T
不需要Sized
,因为它只在引用中使用,所以让我们添加约束T: ?Sized
:
pub struct InnerMut<T: ?Sized> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T: ?Sized> InnerMut<T> {
// …
}
答案 1 :(得分:1)
您遇到的是编译器无法证明您没有将&mut borrow
内的mutate()
引用存储到InnerMut
实例中。这将是有问题的,因为它知道闭包的参数比闭包本身更短。但是InnerMut
已移至关闭状态,且活动时间必须超过borrow
。
基本上Rust会阻止闭包参数转义闭包because it does not know how to infer lifetimes then。
考虑这个最小的例子:
struct Test<T> {
field: fn(T),
}
impl<T> Test<T> {
fn foo(&self, _val: T) {}
}
fn calc(_: &mut i32) {}
fn main() {
let test: Test<&mut i32> = Test { field: calc };
let _ = move |y: i32| {
test.foo(&mut y);
};
}
它以某种方式编写,以便编译器更好地理解它,以便我们能够理解错误:
error[E0597]: `y` does not live long enough
--> src/main.rs:15:23
|
15 | test.foo(&mut y);
| ^ borrowed value does not live long enough
16 | };
| - `y` dropped here while still borrowed
17 | }
| - borrowed value needs to live until here
但我的结构中甚至没有那种类型的字段
Rust的一个关键原则是您的函数签名是错误报告的障碍。根据签名检查函数本身,并根据签名检查调用者。这可以防止将函数体的混淆错误报告给函数的调用者(甚至没有编写它们)。
对于Rust知道的所有内容,您的T
被推断为&mut u[8]
而您的mutate()
会抓住一个可变的自我。这是可疑的。更好地防止关闭变量的潜在逃逸。
但稍微更改代码会使其正常工作
拒绝所有不正确的程序并接受所有正确的程序是不可判定的。因此,Rust会谨慎行事并拒绝正确的程序。因此,一些细微的变化可以使Rust接受该程序,即使该程序之前是正确的。
这对我的代码意味着什么?
我真的不太了解编译器来回答这个问题。我的猜测是,通过将T
更改为[u8]
并且InnerMut
类型缺少显式生存期,编译器可以证明您的闭包变量没有转义。