“变量的寿命不足"返回包含引用的结果但它的寿命足够长时 [英] "Variable does not live long enough" when returning a Result containing a reference but it does live long enough

查看:69
本文介绍了“变量的寿命不足"返回包含引用的结果但它的寿命足够长时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一个小型实用程序,编译器告诉我变量(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆