Why as_ref() will get a mutable reference?

Here is the code:

&TcpStream will be get after self.stream.as_ref().unwrap()
but it compiles ok with calling write which need &mut self

Am I missing about the implicit conversion?

Self is &TcpStream here (instead of TcpStream.)

1 Like

Yes,I got it. Thanks
But write still need a mutable reference for &TcpStream , so it should be a type of &mut &TcpStream that can call the write function.
but in my post, it still a immutable reference( &TcpStream) after self.stream.as_ref().unwrap()

It's trivial to create a &mut &T from a &T given that references are copy.[1] The compiler does so under the hood of method-call expressions:

The first step is to build a list of candidate receiver types. Obtain these by repeatedly dereferencing the receiver expression’s type, adding each type encountered to the list, then finally attempting an unsized coercion at the end, and adding the result type if that is successful. Then, for each candidate T, add &T and &mut T to the list immediately after T.


  1. Irrelevant, see @SebastianJL comment below. ↩︎

1 Like

No, you cannot modify data through a shared reference.
The magic lies in that the inner TcpStream uses internal mutability:

via

Is that even necessary? The compiler will also create a &mut T from a T in methods even when T: !Copy.

2 Likes

Sure, that's the reason why Write can be implemented for &TcpStream. It does not change how Rustc creates a &mut &TcpStream from &TcpStream to satisfy the signature of <&TcpStream as Write>::write.

3 Likes

Of course. Thanks for the correction.

I check the docs, I can't understand why immutable T can be listed as candidate with type of &mut T , This obviously violates the borrowing rule

That does not violate the borrowing rules because you can't mutate TcpStream if you have &mut &TcpStream (the mutability of the outer reference only allows you to change the &TcpStream to be a different immutable reference, i.e. to a different TcpStream). Maybe you find it helpful if we were to desugar your example a bit and use fully qualified syntax instead of relying on method-call resolution?

    fn send(&mut self,data: &[u8])->usize
    {
        let x: Option<&TcpStream> = self.stream.as_ref();
        
        let mut x: &TcpStream = x.unwrap();
        
        <&TcpStream as Write>::write(&mut x, data).unwrap()
    }

Playground.

1 Like

so the mut before x is the key! if T was declared as a mut T(mutable), so it can be listed as candidate with type &mut T ; if T was declared as a T(immutable), the compiler should not use &mut T as a candidate .

What you might missed is that, mutability is a property of binding, not value (or type). You can always write let mut x = x; to declare a new mut binding to the value.

Since your original code snippet, the concerning value is a temporary, it's free to assign a mut binding to it.

4 Likes

Thanks, these words hit my doubts.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.