我在Rust中编写代码来解析流trait Stream
。流可以包含其他流。特征StreamIterator
可以访问子流。这是在解析tar文件,zip文件和其他包含文件的文件时。
在编写此代码时,我没有成功与借阅检查器作斗争。
以下代码是一个简化示例。在main
中,文件作为流打开。该流被传递给analyze
函数,该函数尝试打开流作为TarStreamIterator
来迭代tar中的流。还分析了每个嵌入的流。
我认为我可能会在StreamIterator
特征中引入第二个生命周期。
use std::io;
trait Stream<T> {
fn read(&mut self) -> io::Result<&[T]>;
}
trait StreamIterator<'a,T,S: Stream<T>> {
fn next(&'a mut self) -> Option<io::Result<S>>;
}
struct FileStream {
}
impl<T> Stream<T> for FileStream {
fn read(&mut self) -> io::Result<&[T]> {
Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
}
}
struct TarStream<'a> {
stream: &'a mut Stream<u8>
}
impl<'a> Stream<u8> for TarStream<'a> {
fn read(&mut self) -> io::Result<&[u8]> {
self.stream.read()
}
}
struct TarStreamIterator<'a> {
stream: &'a mut Stream<u8>
}
impl<'a> StreamIterator<'a,u8,TarStream<'a>> for TarStreamIterator<'a> {
fn next(&'a mut self) -> Option<io::Result<TarStream>> {
// todo: read tar header
Some(Ok(TarStream{stream: self.stream}))
}
}
fn analyzeAsTar(s: &mut Stream<u8>) -> bool {
let mut tar = TarStreamIterator{stream: s};
while let Some(Ok(mut substream)) = tar.next() {
analyze(&mut substream);
}
true
}
fn analyze(s: &mut Stream<u8>) -> bool {
analyzeAsTar(s)
}
fn main() {
let mut fs = FileStream{};
analyze(&mut fs);
}
这会出现此错误:
<anon>:38:41: 38:44 error: cannot borrow `tar` as mutable more than once at a time [E0499]
<anon>:38 while let Some(Ok(mut substream)) = tar.next() {
^~~
<anon>:38:41: 38:44 help: see the detailed explanation for E0499
<anon>:38:41: 38:44 note: previous borrow of `tar` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `tar` until the borrow ends
<anon>:38 while let Some(Ok(mut substream)) = tar.next() {
^~~
<anon>:42:2: 42:2 note: previous borrow ends here
<anon>:36 fn analyzeAsTar(s: &mut Stream<u8>) -> bool {
...
<anon>:42 }
答案 0 :(得分:1)
有一种解决方法。可以使用具有next()
函数的特征,而不是具有iterate
函数的特征。在下面的示例中,TarStreamIterator
具有函数iterate
可以接受闭包。 (或者,iterator
可以称为for_each
。)
该实现仍然具有next
功能,但借阅检查器接受此表单。
这个简短的例子实际上并没有对流做任何事情。
use std::io;
// generic version of std::io::Read
trait Stream<T> {
fn read(&mut self) -> io::Result<&[T]>;
}
trait StreamIterator<T> {
// call `f` on each of the streams in the iterator
fn iterate<F>(&mut self, mut f: F) where F: FnMut(&mut Stream<T>);
}
struct FileStream {
}
impl<T> Stream<T> for FileStream {
fn read(&mut self) -> io::Result<&[T]> {
Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
}
}
struct TarStream<'a> {
stream: &'a mut Stream<u8>
}
impl<'a> Stream<u8> for TarStream<'a> {
fn read(&mut self) -> io::Result<&[u8]> {
self.stream.read()
}
}
struct TarStreamIterator<'a> {
stream: &'a mut Stream<u8>
}
impl<'a> TarStreamIterator<'a> {
// pass the next embedded stream or None if there are no more
fn next(&mut self) -> Option<TarStream> {
Some(TarStream{stream: self.stream})
}
}
impl<'a> StreamIterator<u8> for TarStreamIterator<'a> {
fn iterate<F>(&mut self, mut f: F) where F: FnMut(&mut Stream<u8>) {
while let Some(mut substream) = self.next() {
f(&mut substream);
}
}
}
fn analyze_as_tar(stream: &mut Stream<u8>) {
TarStreamIterator{stream: stream}.iterate(|substream| {
analyze(substream);
});
}
fn analyze(s: &mut Stream<u8>) {
analyze_as_tar(s)
}
fn main() {
let mut fs = FileStream{};
analyze(&mut fs);
}