【问题标题】:Why can I just pass an immutable reference to BufReader, instead of a mutable reference? [duplicate]为什么我可以只将不可变引用传递给 BufReader,而不是可变引用? [复制]
【发布时间】:2016-03-26 08:29:00
【问题描述】:

我正在编写一个简单的基于 TCP 的回显服务器。当我尝试使用BufReaderBufWriter 读取和写入TcpStream 时,我发现将TcpStream 按值传递给BufReader::new() 会移动其所有权,因此我无法将其传递给BufWriter。然后,我在this thread找到了解决问题的答案:

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() 的不可变引用,而不是可变引用?

整个程序可以在here找到。

更多详情

在上面的代码中,我使用了reader.read_line(&mut message)。于是我打开了Rust标准库中BufRead的源代码,看到了这个:

fn read_line(&mut self, buf: &mut String) -> Result<usize> {
    // ignored
    append_to_string(buf, |b| read_until(self, b'\n', b))
}

在这里我们可以看到它将自我(在我的情况下可能是&amp;mut BufReader)传递给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);
        }
    }
}

在这一部分中,有两个地方使用了BufReaderr.fill_buf()r.consume(used)。我以为r.fill_buf() 是我想看到的。于是,我去Rust标准库中BufReader的代码,发现是这样的:

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(&amp;mut self.buf)self.inner 读取数据。然后,我们来看看BufReaderBufReader::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 可能是&amp;TcpStream

我知道Read.read()的签名是:

fn read(&mut self, buf: &mut [u8]) -> Result<usize>

这里需要一个可变引用,但我只借给它一个不可变引用。当程序在 fill_buf() 中到达 self.inner.read() 时,这应该是一个问题吗?

【问题讨论】:

标签: reference rust immutability borrowing


【解决方案1】:

快速分析器:我们将&amp;TcpStream 传递为R: Read,而不是TcpStream。因此self 中的Read::read&amp;mut &amp; TcpStream,而不是&amp;mut TcpStreamRead&amp;TcpStream 的实现,如您所见 in the documentation

看看这个工作代码:

let stream = TcpStream::connect("...").unwrap();
let mut buf = [0; 100];
Read::read(&mut (&stream), &mut buf);

请注意,stream 甚至没有绑定为 mut,因为我们使用它是不可变的,只是对不可变的引用具有可变引用。


接下来,你可能会问为什么Read 可以为&amp;TcpStream 实现,因为在读取操作期间有必要改变一些东西

这是美好的 Rust 世界 ? ☮ 结束的地方,而邪恶的 C-/操作系统世界开始了 ?。例如,在 Linux 上,您有一个简单的整数作为流的“文件描述符”。您可以将其用于流上的所有操作,包括读取和写入。由于您按值传递整数(它也是Copy-type),因此您可以复制整数的可变或不可变引用。

因此,操作系统或 Rust std 实现必须完成最少量的同步,因为通过不可变引用进行变异通常是奇怪和危险的。这种行为称为“内部可变性”,您可以阅读更多关于它的信息...

【讨论】:

  • 我完全没想到self&amp;mut &amp; TcpStream!!但是,它到底是什么?我的意思是...什么是对引用的可变引用?如果我打电话给self.something,当selfTcpStream&amp;TcpStream 时会产生同样的效果吗?
  • @YushanLin 会有同样的效果 -> 在这种情况下是的。点语法做了一些事情,比如 deref-coercions。这个话题太大了,无法跟进评论^_^
  • 好的。感谢您的回复。您关于为什么Read 可以实现不可变引用的补充很有用!你的回答对我帮助很大。
猜你喜欢
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 1970-01-01
  • 2011-02-27
  • 2022-01-07
  • 2015-12-23
相关资源
最近更新 更多