rust - 返回包含引用的结果时“变量的寿命不够长”,但它的寿命确实足够长
问题描述
我正在实现一个小实用程序,编译器告诉我变量 (a TcpStream
) 的寿命不够长,并建议我找到一种方法让它与当前的寿命一样长。
错误信息
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 的值。如果我更换
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),
}
问题解决了,但我不知道为什么。
解决方案
您的问题可以简化为:
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
.
在代码中添加一些显式的生命周期(出于教育目的,这不会编译),代码看起来像这样:
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
需要 a &mut Reader
,因此编译器会插入一些代码来为您对齐这两种类型。编译器必须对如何执行此转换保持保守,因此它选择较短的生命周期:
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)
问题的下一个方面是这两个函数都使用了生命周期省略。它们的扩展形式如下:
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
,而不是生命周期'stream
。这说明了为什么会出现编译器错误:您试图返回一个Errors
只能存在于函数内部的变量(变量本身的生命周期stream
),但您试图返回一个需要更长时间的引用。
我们可以通过只传递stream
给来解决这个问题handle_request
:
handle_request(stream)?;
不幸的是,这只改变了错误:
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
这部分很难解释。看:
这是目前 Rust 的一个非常粗糙的边缘,但它越来越接近被修复!但是,现在,您有两个主要选择:
调用该函数两次
这可能不起作用,因为您无法从流中读取两次,但在其他情况下它可能有用:
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!();
}
为了提高效率,我会使用迭代器编写:
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let array = (0..0)
.map(|_| handle_request(stream))
.collect::<Result<Vec<_>, _>>()?;
unimplemented!();
}
未来?
使用不稳定的NLL 功能和实验性的“Polonius”实现,这段代码可以工作:
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!();
}
这将需要一段时间才能普遍使用......
推荐阅读
- r - 用str_count计算字符串中的点数?
- python - 过滤多边形之间的点
- linear-regression - 多元线性回归:TensorFlow vs Excel
- javascript - D3.js v5 schemeCategory 库未定义
- c++ - 保留向量段错误
- omnet++ - 如何在静脉版本 5 中将车辆的节点 ID、方向和速度存储在 RSU 中?
- javascript - Сheck 对象字段以查找与本机 javascript 上的指定条件匹配的数据
- xml - XPATH:将根节点添加到节点集
- php - 如何将从用户收到的数据传输到json
- sql - 根据日期标准增加价值