2016-03-26 5 views
2

私は単純なTCPベースのエコーサーバを作成しています。 BufReaderBufWriterを使用してTcpStreamに読み書きしようとすると、TcpStreamBufReader::new()に渡すと所有権が移動し、BufWriterに渡すことができませんでした。なぜ可変参照ではなく、BufReaderへの不変参照を渡すだけですか?

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 
} 

これはシンプルであり、それは動作します:その後、私は問題を解決this threadで答えを見つけました。しかし、私はこのコードがなぜ機能するのかを理解できません。変更可能な参照ではなく、BufReader::new()への不変参照を渡すのはなぜですか?

プログラム全体はhereです。上記のコードで

詳細

、Iはreader.read_line(&mut message)を用います。だから私は錆標準ライブラリにBufReadのソースコードを開いて、この見た:ここ

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

を我々はそれがread_until()に(私の場合は&mut BufReaderてもよい)、自己を渡していることがわかります。次に、私は同じファイルに次のコードを見つけました:r.fill_buf()r.consume(used):この部分で

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を使用して2つの場所があります。私はr.fill_buf()が私が見たいと思っていたと思った。したがって、私は錆標準ライブラリにBufReaderのコードに行って、これを見つけた:それはself.innerからデータを読み取るためにself.inner.read(&mut self.buf)を使用するように

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]) 
} 

に思えます。その後、我々は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 
} 

上記のコードから、我々はinnerReadを実装する型であることを知ることができます。私の場合、inner&TcpStreamです。

私はRead.read()の署名を知っていたが、次のとおりです。

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

ここは可変参照が必要ですが、私はそれを不変参照を貸しました。これは、self.inner.read()fill_buf()に達すると問題になるのでしょうか?

+0

で[なぜそれが読んで実現することが可能であるの重複ファイルへの不変参照?](http://stackoverflow.com/q/31503488/155423)。 – Shepmaster

+0

@Shepmaster私は当初、TcpStreamがFileとは異なる方法で動作すると考えました。しかし、Lukas Kalbertodtの答えを読んだ後、私は突然、その背後にある考え方は同じであることに気付きました。あなたのリンクをありがとう。 –

答えて

2

クイックANSER:我々はないTcpStreamR: Readとして&TcpStreamを渡します。従って、Read::readself&mut & TcpStreamであり、&mut TcpStreamではない。 in the documentationのようにRead&TcpStreamに実装されています。この作業コードで

ルック:

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

我々はimmutablyそれを使用しているためstreamはただでさえ不変1の可変の参照を持つ、mutとしてバインドされていないことに注意してください。


それは読み出し動作中何かを変異させる必要がありますのでReadは、&TcpStreamのために実装することができ、なぜ、あなたが求めることができます。

これは素晴らしいRust-world☮が終了し、悪いC-/operating system-worldが始まるところです。たとえば、Linuxでは、ストリームの「ファイル記述子」として単純な整数が使用されます。これは、ストリームのすべての操作(読み書きを含む)に使用できます。整数を値で渡すので(それはCopy型でもあります)、整数に変更可能または不変の参照があるかどうかは問題ではありません。

したがって、オペレーティングシステムまたはRust stdの実装によって最小限の同期化が行われなければなりません。通常、不変の参照によって突然変異するのは奇妙で危険です。この動作は、「内部可変性」と呼ばれ、あなたはそれについて少し詳細を読むことができ... the cell documentation

  • +0

    私はまったく 'self'が'&mut&TcpStream'だとは思わなかった!!しかし、それは正確に何ですか?私は、リファレンスへの変更可能な参照は何ですか? 'self.something'と呼んだ場合、' self'が 'TcpStream'や'&TcpStream'のときと同じ効果がありますか? –

    +0

    @YushanLin *は同じ効果を持ちます* - >この場合はyesです。ドット構文は、逆参照変換のようないくつかのことを行います。このトピックは余分なコメントのためには大きすぎます^ _^ –

    +0

    お返事をありがとうございます。 'Read'が不変のリファレンスのためになぜ実装できるのかについてのあなたの補足は有用です!あなたの答えが私を助けます。 –

    関連する問題