単純な TCP ベースのエコー サーバーを作成しています。を使用BufReader
しBufWriter
て a から読み書きしようとしたとき、 aを値で渡すとその所有権が移動し、 a に渡すことができないことがTcpStream
わかりました。次に、このスレッドで問題を解決する答えを見つけました。TcpStream
BufReader::new()
BufWriter
fn handle_client(stream: TcpStream) {
let mut reader = BufReader::new(&stream);
let mut writer = BufWriter::new(&stream);
// Receive a message
let mut message = String::new();
reader.read_line(&mut message).unwrap();
// ingored
}
これは簡単で、うまくいきます。ただし、このコードが機能する理由がよくわかりません。可変参照ではなく、不変参照を に渡すことができるのはなぜBufReader::new()
ですか?
プログラム全体はここにあります。
詳細
上記のコードでは、 を使用しreader.read_line(&mut message)
ました。BufRead
それで、Rust標準ライブラリのソースコードを開いて、これを見ました:
fn read_line(&mut self, buf: &mut String) -> Result<usize> {
// ignored
append_to_string(buf, |b| read_until(self, b'\n', b))
}
&mut BufReader
ここで、自己 (私の場合は a かもしれません) を に渡していることがわかりますread_until()
。次に、同じファイル内に次のコードを見つけました。
fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
-> Result<usize> {
let mut read = 0;
loop {
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e)
};
match memchr::memchr(delim, available) {
Some(i) => {
buf.extend_from_slice(&available[..i + 1]);
(true, i + 1)
}
None => {
buf.extend_from_slice(available);
(false, available.len())
}
}
};
r.consume(used);
read += used;
if done || used == 0 {
return Ok(read);
}
}
}
この部分では、BufReader
:r.fill_buf()
とを使用している場所が 2 つありr.consume(used)
ます。私r.fill_buf()
が見たいものだと思いました。BufReader
したがって、 Rust標準ライブラリのコードに行き、これを見つけました:
fn fill_buf(&mut self) -> io::Result<&[u8]> {
// ignored
if self.pos == self.cap {
self.cap = try!(self.inner.read(&mut self.buf));
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}
self.inner.read(&mut self.buf)
からデータを読み取るために使用しているようself.inner
です。BufReader
次に、との構造を見てみましょうBufReader::new()
。
pub struct BufReader<R> {
inner: R,
buf: Vec<u8>,
pos: usize,
cap: usize,
}
// ignored
impl<R: Read> BufReader<R> {
// ignored
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
// ignored
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
buf: vec![0; cap],
pos: 0,
cap: 0,
}
}
// ignored
}
inner
上記のコードから、が を実装する型であることがわかりますRead
。私の場合、inner
は&TcpStream
.
の署名Read.read()
は次のとおりです。
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
ここでは可変参照が必要ですが、不変参照のみを貸与しました。self.inner.read()
プログラムが に到達したとき、これは問題になるはずfill_buf()
ですか?