我想要TcpStream
和BufReader
共享的BufWriter
,我在以下位置找到了解决方案:
If BufReader takes ownership of a stream, how can I read and write lines on it?
现在我想要它自己的数据结构,但是我只能从以下部分得到答案:
Why can't I store a value and a reference to that value in the same struct?
use std::io::{BufReader, BufWriter};
use std::net::TcpStream;
pub struct BufTcpStream<'a> {
_socket: TcpStream,
input: BufReader<&'a TcpStream>;
output: BufWriter<&'a TcpStream>;
}
impl<'a> BufTcpStream<'a> {
pub fn new(socket: TcpStream) -> Self {
Self{
input : BufReader::new(&socket),
output: BufWriter::new(&socket),
_socket: socket,// <-- MOVE OF BORROWED VALUE HERE
}
}
}
要解决此问题,我必须确保TcpStream
引用在整个结构生存期内均保持有效,我使用了Pin<Box<TcpStream>>
来确保它有效。
但是编译器仍然抱怨借入值socket
的移动。为了消除此障碍,我使用了std::meme::transmute()
。
现在,我想知道的是:
use std::io::{BufReader, BufWriter};
use std::net::TcpStream;
use std::pin::Pin;
pub struct BufTcpStream<'a> {
_socket: Pin<Box<TcpStream>>,
input : BufReader<&'a TcpStream>,
output: BufWriter<&'a TcpStream>,
}
impl<'a> BufTcpStream<'a> {
pub fn new(socket: TcpStream) -> Self {
let pin = Box::pin(socket);
unsafe {
Self{
input : BufReader::new(std::mem::transmute(&*pin)),
output: BufWriter::new(std::mem::transmute(&*pin)),
_socket: pin,
}
}
}
pub fn reach(&mut self) -> (
&mut BufReader<&'a TcpStream>,
&mut BufWriter<&'a TcpStream>
) {
(&mut self.input, &mut self.output)
}
}
答案 0 :(得分:1)
使用TcpStream::try_clone
获得第二个视频流:
返回的
TcpStream
是对该对象引用的同一流的引用。 两个句柄都将读取和写入相同的数据流,并且在一个流上设置的选项将传播到另一个流。
然后,您可以将一个包装在读者中,将一个包装在作者中:
use std::{
io::{self, BufReader, BufWriter},
net::TcpStream,
};
struct BufTcpStream {
input: BufReader<TcpStream>,
output: BufWriter<TcpStream>,
}
impl BufTcpStream {
fn new(stream: TcpStream) -> io::Result<Self> {
let input = BufReader::new(stream.try_clone()?);
let output = BufWriter::new(stream);
Ok(Self { input, output })
}
}
另请参阅:
答案 1 :(得分:-1)
TcpStream
的引用的生存期可能比结构本身的生存期长let bad_ref = {
let buffer = BufTcpStream::new(...);
let (i, o) = buffer.reach();
*i.get_ref()
};// <-- buffer is dropped here
// bad_ref is now an invalid ref but the compiler won't see it
bad_ref.write(b"hello world").unwrap();
*i.get_ref()
的类型为&'a TcpStream
,但是&'a
的生存期永远不会被编译器推断出来,因此不会考虑在内。
可以通过将reach()
的生存期链接到返回的引用来在self
方法中进行修复:
fn reach<'b>(&'b mut self) -> (
&mut BufReader<&'b TcpStream>,
&mut BufWriter<&'b TcpStream>
) {
(&mut self.input, &mut self.output)
}
TcpStream
在BufReader
和BufWriter
之前被删除pub struct BufTcpStream<'a> {
_socket: Pin<Box<TcpStream>>,// First to be dropped |
input : BufReader<&'a TcpStream>,// Second to be dropped |
output: BufWriter<&'a TcpStream>,// Last to be dropped V
}
可以通过将_socket
作为最后一个元素来解决此问题:
pub struct BufTcpStream<'a> {
input : BufReader<&'a TcpStream>,// First to be dropped |
output: BufWriter<&'a TcpStream>,// Second to be dropped |
_socket: Pin<Box<TcpStream>>,// Last to be dropped V
}
实际上,'a
中的struct BufTcpStream<'a>
生存期是没有用的。
可以将不安全引用的生存期设置为'static
。
use std::io::{BufReader, BufWriter};
use std::net::TcpStream;
use std::pin::Pin;
pub struct BufTcpStream {
input : BufReader<&'static TcpStream>,
output: BufWriter<&'static TcpStream>,
_socket: Pin<Box<TcpStream>>,
}
impl BufTcpStream {
pub fn new(socket: TcpStream) -> Self {
let pin = Box::pin(socket);
unsafe {
Self{
input : BufReader::new(std::mem::transmute(&*pin)),
output: BufWriter::new(std::mem::transmute(&*pin)),
_socket: pin,
}
}
}
pub fn reach<'b>(&'b mut self) -> (
&mut BufReader<&'b TcpStream>,
&mut BufWriter<&'b TcpStream>
) {
unsafe {
std::mem::transmute((&mut self.input, &mut self.output))
}
}
}