“变量的寿命不足"返回包含引用的结果但它的寿命足够长时 [英] "Variable does not live long enough" when returning a Result containing a reference but it does live long enough
问题描述
我正在实现一个小型实用程序,编译器告诉我变量(a TcpStream
)的生存期不够长,并建议我找到一种使该生存期与当前生存期完全相同的方法
I'm implementing a small utility and the compiler is telling me that a variable (a TcpStream
) does not live long enough and is advising me to find a way to make it live exactly as long as it is currently living.
error[E0597]: `stream` does not live long enough
--> src/main.rs:47:35
|
47 | match handle_request(&mut stream){
| ^^^^^^ borrowed value does not live long enough
...
54 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 43:1...
--> src/main.rs:43:1
|
43 | / fn handle_array(stream: &mut BufReader<TcpStream>) -> Result<Data,Errors>
44 | | {
45 | | let mut array: Vec<Data> = Vec::with_capacity(50);//arbitrary size, picked differently in the complete program
46 | | for _x in 0..50 {
... |
53 | | Ok(Data::Array(array))
54 | | }
| |_^
代码
use std::collections::HashMap;
use std::io::BufReader;
use std::io::Read;
use std::net::TcpStream;
static TOKEN: &[u8; 2] = b"\r\n";
fn main() {}
#[derive(Debug, Clone)]
pub enum Data {
String(Vec<u8>),
Error(Vec<u8>),
Integer(i64),
Binary(Vec<u8>),
Array(Vec<Data>),
Dictionary(HashMap<String, Data>),
}
#[derive(Debug, Clone)]
pub enum Errors<'a> {
CommandError(&'a str),
EndOfConnection,
NotImplemented,
}
pub fn handle_request(stream: &mut BufReader<TcpStream>) -> Result<Data, Errors> {
//TODO handle the empty stream
let mut buff: [u8; 1] = *b"0";
stream.read_exact(&mut buff); //TODO: handle error here
match &buff {
/* part skipped, not relevant */
b"*" => handle_array(stream),
&[_] => Err(Errors::CommandError("Bad request")),
}
}
/*part skipped, not relevant */
fn handle_array(stream: &mut BufReader<TcpStream>) -> Result<Data, Errors> {
let mut array: Vec<Data> = Vec::with_capacity(50); //arbitrary size, picked differently in the complete program
for _x in 0..50 {
match handle_request(&mut stream) {
Ok(x) => array.push(x.clone()),
Err(x) => return Err(x.clone()),
}
}
Ok(Data::Array(array))
}
我真的很喜欢这个.
似乎我无法使用Err的值.如果我更换
It seems that I can't use the value of the Err. If I replace
match handle_request(&mut stream){
Ok(x) => array.push(x.clone()),
Err(x) => return Err(x.clone()),
}
使用
match handle_request(&mut stream){
Ok(x) => array.push(x.clone()),
Err(_) => return Err(Errors::NotImplemented),
}
问题已解决,但我不知道为什么.
the problem is solved, but I don't know why.
推荐答案
您的问题可以减少为:
struct Reader;
struct Data;
struct Errors<'a>(&'a str);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
for _ in 0..0 {
handle_request(&mut stream)?;
}
unimplemented!();
}
fn handle_request(_stream: &mut Reader) -> Result<Data, Errors> {
unimplemented!()
}
fn main() {}
error[E0597]: `stream` does not live long enough
--> src/main.rs:7:29
|
7 | handle_request(&mut stream)?;
| ^^^^^^ borrowed value does not live long enough
...
11 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 5:1...
--> src/main.rs:5:1
|
5 | / fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
6 | | for _ in 0..0 {
7 | | handle_request(&mut stream)?;
8 | | }
9 | |
10 | | unimplemented!();
11 | | }
| |_^
在handle_array
的主体中,stream
的类型为&mut Reader
.但是,在调用handle_request
时,您对其进行另一个引用,从而创建一个&mut &mut Reader
.
In the body of handle_array
, stream
is of type &mut Reader
. However, when calling handle_request
, you take another reference to it, creating a &mut &mut Reader
.
在代码中添加一些明确的生命周期(出于教育目的,这不会编译),代码看起来像这样:
Adding some explicit lifetimes to the code (for educational purposes, this doesn't compile), the code would look kind of like this:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors> {
let tmp: &'tmp mut &'stream mut Reader = &mut stream;
if let Err(x) = handle_request(tmp)
handle_request
需要一个&mut Reader
,因此编译器会插入一些代码来为您对齐这两种类型.编译器必须保守其执行转换的方式,因此会选择较短的生存期:
handle_request
requires a &mut Reader
, so the compiler inserts some code to align these two types for you. The compiler has to be conservative about how it performs this conversion, so it picks the shorter lifetime:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors> {
let tmp: &'tmp mut &'stream mut Reader = &mut stream;
let tmp2: &'tmp mut Reader = tmp;
if let Err(x) = handle_request(tmp2)
问题的下一个方面是,终生淘汰制已在这两个功能中发挥作用.它们的扩展形式如下:
The next aspect of the problem is that lifetime elision has kicked in for both functions. Their expanded forms look like:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors<'stream>>
fn handle_request<'_stream>(_stream: &_stream mut Reader) -> Result<Data, Errors<'_stream>>
这意味着返回的Errors
的生存期与参数的生存期相关,但是在您的情况下,handle_request
的参数的'tmp
生存期较短, not 'stream
的寿命.这说明了为什么会出现编译器错误:您试图返回一个只能在函数内部 中生存的Errors
(变量stream
本身的生存期),但是您试图返回需要更长寿命的参考.
This means that the lifetime of the returned Errors
is tied to the lifetime of the argument, but in your case, the argument to handle_request
has the shorter 'tmp
lifetime, not the lifetime of 'stream
. This shows why you get the compiler error: You are trying to return an Errors
that can only live inside the function (the lifetime of the variable stream
itself), but you are trying to return a reference that needs to live longer.
我们可以通过仅将stream
传递给handle_request
来解决此问题:
We can solve this by only passing stream
to handle_request
:
handle_request(stream)?;
不幸的是,这只会更改错误:
Unfortunately, this only changes the error:
error[E0499]: cannot borrow `*stream` as mutable more than once at a time
--> src/main.rs:9:40
|
9 | if let Err(x) = handle_request(stream) {
| ^^^^^^ mutable borrow starts here in previous iteration of loop
...
15 | }
| - mutable borrow ends here
这部分很难解释.参见:
This part is much harder to explain. See:
- "Problem Case #3" of the Non-Lexical Lifetimes RFC (RFC 2094)
- Cannot borrow `x` as mutable more than once at a time
- Cannot borrow node as mutable more than once while implementing a binary search tree
这是Rust目前的一个非常粗糙的边缘,但是它越来越难以修复!但是,现在您有两个主要选择:
This is a really rough edge of Rust's right now, but it's getting closer and closer to being fixed! Right now, however, you have two main choices:
这可能不起作用,因为您无法两次从流中读取内容,但是在其他情况下,它可能会很有用:
This probably won't work because you can't read from the stream twice, but in other cases it might be useful:
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in 0..0 {
if handle_request(stream).is_err() {
return handle_request(stream);
}
if let Ok(r) = handle_request(stream) {
array.push(r);
};
}
unimplemented!();
}
删除参考
放弃尝试在这种情况下暂时提供引用 .
struct Errors(String);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in 0..0 {
array.push(handle_request(stream)?);
}
unimplemented!();
}
我会使用迭代器来提高效率:
Which I'd write using iterators for efficiency:
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let array = (0..0)
.map(|_| handle_request(stream))
.collect::<Result<Vec<_>, _>>()?;
unimplemented!();
}
未来?
具有不稳定 NLL功能和实验性"Polonius"实现,此代码有效:
The future?
With the unstable NLL feature and the experimental "Polonius" implementation, this code works:
struct Errors<'a>(&'a str);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in (0..0) {
array.push(handle_request(stream)?);
}
unimplemented!();
}
要等一会儿才可以使用...
It will just be a while before this is generally available...
这篇关于“变量的寿命不足"返回包含引用的结果但它的寿命足够长时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!