Arc<T>内部数据为何可变?关于Arc<(TcpStream, SocketAddr)>调用read_to_string()的疑问
这其实是Rust中内部可变性和trait实现范围共同作用的结果,咱们一步步拆解清楚:
Arc的解引用特性
Arc只实现了 Deref<Target = T>,所以arced.0会自动解引用成&TcpStream——也就是内部TcpStream的不可变引用,这也是你没法直接写&mut arced.0的原因,毕竟Arc本身不支持可变解引用。TcpStream的特殊Read实现
这是核心关键点:标准库不仅给TcpStream本身实现了Readtrait,还专门为**&TcpStream**(也就是TcpStream的不可变引用)也实现了Read!大概是这样的逻辑:impl Read for &TcpStream { // 内部利用UnsafeCell实现的内部可变性完成读操作 fn read(&mut self, buf: &mut [u8]) -> Result<usize> { // ...底层套接字的读逻辑 } }TcpStream的读操作本质上不需要修改外部可见的结构体状态,底层的套接字状态变化是通过内部可变性安全处理的,所以即使是不可变引用也能完成读操作。
read_to_string的调用适配
read_to_string是Readtrait的方法,它的签名是:fn read_to_string(&mut self, buf: &mut String) -> Result<usize>当你拿着
&TcpStream调用这个方法时,Rust会自动把&TcpStream转换成&mut &TcpStream——这里的“可变”只是针对引用本身的可变,而非指向的TcpStream的可变。而因为&TcpStream已经实现了Read,这个&mut &TcpStream完全符合方法对&mut self的要求,所以调用就能正常生效。
简单总结:你看似是用不可变的TcpStream引用调用了需要可变self的方法,但实际上调用的是针对&TcpStream的专属Read实现,这个实现允许通过不可变引用完成读操作,方法要求的&mut self只是针对这个引用本身的可变,和TcpStream的可变性无关。
内容的提问来源于stack exchange,提问作者thedenisnikulin

