我正在写一个应该从实现BufRead特性的东西中读取的库; 网络数据流,标准输入等.第一个函数应该从该读取器读取数据单元并返回一个填充的结构,该结构主要填充有&'a str从线路中的帧解析的值.
这是一个最小版本:
mod mymod {
use std::io::prelude::*;
use std::io;
pub fn parse_frame<'a, T>(mut reader: T)
where
T: BufRead,
{
for line in reader.by_ref().lines() {
let line = line.expect("reading header line");
if line.len() == 0 {
// got empty line; done with header
break;
}
// split line
let splitted = line.splitn(2, ':');
let line_parts: Vec<&'a str> = splitted.collect();
println!("{} has value {}", line_parts[0], line_parts[1]);
}
// more reads down here, therefore the reader.by_ref() above
// (otherwise: use of moved value).
}
}
use std::io;
fn main() {
let stdin = io::stdin();
let locked = stdin.lock();
mymod::parse_frame(locked);
}
Run Code Online (Sandbox Code Playgroud)
在尝试不同的解决方案后,出现了一个我无法解决的错误:
error: `line` does not live long enough
--> src/main.rs:16:28
|
16 | let splitted = line.splitn(2, ':');
| ^^^^ does not live long enough
...
20 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 8:4...
--> src/main.rs:8:5
|
8 | / {
9 | | for line in reader.by_ref().lines() {
10 | | let line = line.expect("reading header line");
11 | | if line.len() == 0 {
... |
22 | | // (otherwise: use of moved value).
23 | | }
| |_____^
Run Code Online (Sandbox Code Playgroud)
生命周期'a是在数据保持器结构的结构和实现上定义的,因为它&str需要明确的生命周期.这些代码部分作为最小示例的一部分被删除.
BufReader有一个lines()返回的方法Result<String, Err>.我使用expect或处理错误match,从而解压缩,Result以便程序现在没有String.然后将多次执行此操作以填充数据结构.
许多答案都说unwrap结果需要绑定到一个变量,否则它会丢失,因为它是一个临时值.但我已经将解压缩的Result值保存在变量中line,但我仍然得到错误.
如何修复此错误 - 无法在数小时后尝试使其正常工作.
&str在数据管理器结构中执行所有这些生命周期声明是否有意义?这将主要是一个只读数据结构,最多取代整个字段值.String也可以使用,但发现文章说String性能低于&str- 并且这个框架解析器函数将被多次调用并且对性能至关重要.
Stack Overflow上存在类似的问题,但没有一个能够解决这里的情况.
为了完整性和更好的理解,以下是完整源代码的摘录,为什么会出现终身问题:
数据结构声明:
// tuple
pub struct Header<'a>(pub &'a str, pub &'a str);
pub struct Frame<'a> {
pub frameType: String,
pub bodyType: &'a str,
pub port: &'a str,
pub headers: Vec<Header<'a>>,
pub body: Vec<u8>,
}
impl<'a> Frame<'a> {
pub fn marshal(&'a self) {
//TODO
println!("marshal!");
}
}
Run Code Online (Sandbox Code Playgroud)
完整的功能定义:
pub fn parse_frame<'a, T>(mut reader: T) -> Result<Frame<'a>, io::Error> where T: BufRead {
Run Code Online (Sandbox Code Playgroud)
你的问题可以减少到这个:
fn foo<'a>() {
let thing = String::from("a b");
let parts: Vec<&'a str> = thing.split(" ").collect();
}
Run Code Online (Sandbox Code Playgroud)
String在函数内部创建,然后声明对该字符串的引用保证在生命周期内存活'a.不幸的是,生命周期'a 不在你的控制之下 - 函数的调用者可以选择生命周期.这就是通用参数的工作方式!
如果函数的调用者指定了'static生命周期会发生什么?如何在运行时分配值的代码可以保证值的寿命比main函数更长?这是不可能的,这就是编译器报告错误的原因.
一旦你获得了更多的经验,函数签名fn foo<'a>()将像红色警报一样跳出来 - 有一个未使用的泛型参数.这很可能意味着坏消息.
返回一个主要填充的填充结构
&'a str
您不可能使用当前的代码组织来执行此操作.参考文献必须指出一些事情.您没有提供指向值的任何地方.您不能将已分配String的字符串返回.
在跳转到它之前,不能在同一个结构中存储值和对该值的引用.
相反,您需要拆分创建的代码String和解析它的代码&str并返回更多&str引用.这就是所有现有的零拷贝解析器的工作方式.你可以看看那些灵感.
String性能低于&str
不,它确实没有.创造许多无关String的东西是个坏主意,当然,就像分配太多在任何语言中都是一个坏主意一样.
| 归档时间: |
|
| 查看次数: |
553 次 |
| 最近记录: |