为什么在可变字符串引用上调用可变方法不起作用,但 TcpStream 上可以?

4

当我试图理解一个可变变量(是一个引用),例如 let mut x: &i32 和可变引用,例如 let x: &mut i32 之间的区别时,我发现了这个我无法理解的差异:

以下代码可以正常工作,其中 by_ref 具有如下签名:fn by_ref(&mut self) -> &mut Self (文档)

fn example(mut t: &TcpStream) {
    t.by_ref();
}

但是使用类似签名的方法 reserve,对于以下的String 类型的情况,则不同:

pub fn reserve(&mut self, additional: usize)`

但是这种方法行不通,错误提示是:
“无法将 *str 作为可变引用来借用,因为它在 & 引用之后”
fn example(mut str: &String) {
    str.reserve(10);
}

有趣的是,这两个使用可变引用的示例可以正常工作,并且据我所知,这也是推荐的使用可变方法的方式:

fn example_stream(t: &mut TcpStream) {
    t.by_ref();
}

fn example_string(str: &mut String) {
    str.reserve(10);
}

那么一个 TcpStream 和一个 String 之间有什么不同,使得一个可以调用具有 &mut self 参数的方法,而另一个不行?
1个回答

5

你所使用的 TcpStream 例子有误导性。

你链接的是实现了 impl Read for TcpStream,但其实还有一个实现了 impl Read for &TcpStream。你所使用的是后者,它不需要对 TcpStream 进行可变访问,只需要对指向 TcpStream 的可变引用 t 进行可变访问。

这样实现的原因是 Read 特质使用可变方法允许读取需要改变或独占访问的读器。然而,TcpStream 实际上不需要改变或独占访问来读取数据,因为它基本上只是将系统调用推迟处理。因此,通过在其引用上实现 ReadTcpStream 可以更加灵活,并且允许多个线程从套接字读/写。

另一方面,str.reserve() 调用没有这种灵活性,需要对 String 进行可变访问,因此 &String 是不够的。


1
太棒了,非常感谢!我有一种预感它与实现特征有关,但是无法想出来,并且我不知道特征也可以在引用类型上实现。这是一个完美的答案,再次感谢! - pjam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接