![](/img/trans.png)
[英]How can I fix “cannot infer an appropriate lifetime for autoref” when implementing an iterator that returns mutable references?
[英]Why do I get the error “cannot infer an appropriate lifetime for lifetime parameter in generic type” when using nested mutable references?
編碼時習慣了Rust,我偶然發現編譯錯誤。 我想了解為什么我得到錯誤以及如何處理它:
由於需求沖突,無法推斷泛型類型的生命周期參數的適當生命周期
我一直在研究很多涉及類似錯誤的問題,但大多數似乎與循環依賴有關,我不認為這就是這里發生的事情。
這是我對MWE的嘗試,它仍然可以進一步減少:
游樂場鏈接 (略有不同的錯誤信息)
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;
| ^^^^^^^^^^^^^
我不可能想到&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> {
// …
}
您遇到的是編譯器無法證明您沒有InnerMut
mutate()
內部的&mut borrow
的引用存儲到您的InnerMut
實例中。 這將是有問題的,因為它知道閉包的參數比閉包本身更短。 但是InnerMut
被轉移到關閉,並且必須比borrow
更長壽。
基本上Rust會阻止閉包參數轉義, 因為它不知道如何推斷生命周期 。
考慮這個最小的例子:
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()
捕獲了一個可變的self。 這是可疑的。 更好地防止封閉變量的潛在逃逸。
但稍微更改代碼使其工作
拒絕所有不正確的程序並接受所有正確的程序是不可判定的。 因此,Rust會謹慎行事並拒絕正確的程序。 因此,即使程序之前正確,一些輕微的更改也可以使Rust接受該程序。
這對我的代碼意味着什么?
我真的不太了解編譯器來回答這個問題。 我的猜測是,通過將T
更改為[u8]
並且缺少來自InnerMut
類型的顯式生存期,編譯器可以證明您的閉包變量沒有轉義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.