和...之间的不同&*conn
and conn.borrow()
就是它一个类型可以有多个 Borrow impl.
use std::borrow::Borrow;
fn main() {
let input = vec![1, 2, 3];
let _slice: &[u8] = input.borrow(); // ok
let _vec_ref: &Vec<u8> = input.borrow(); // also ok
let _slice: &[u8] = &*input; // ok
// let _vec_ref: &Vec<u8> = &*input; // error!
}
The &*conn
表达式使用Deref特征,其中每种类型只能有一个Deref
执行。然而,一个类型可以有多个Borrow<X>
针对不同的实现X
s.
当你写的时候
read_exact(conn.borrow(), [0u8]);
编译器需要解决以下义务:
-
Rc<TcpStream>: Borrow<X1>
由于使用borrow()
-
&X1: AsyncRead
due to read_exact
注意X1
是未知类型。编译器需要找出所有潜在的X1
看看是否有人能够履行这两项义务。义务 2 以某种方式首先得到评估,最终得到这些候选者:
-
impl AsyncRead for &[u8]
可能还有更多不重要的候选人......
同样,不知何故,候选人 1 在候选人 2 之前被选中。这导致在选择候选人 1 后出现以下一组新义务:
Rc<TcpStream>: Borrow<PollEvented<X2>>
-
&PollEvented<X2>: AsyncRead
solved!
&X2: Read
然后导致impl<X3> Read for &PollEvented<X3> where &X3: Read
被选中,从此时起,求解器陷入无限循环并最终放弃。
有关编译器如何求解这些方程的详细信息可以在Rust 编译器指南.
好消息是特质系统正在开发中revamped使用标准逻辑推理技术(如 Prolog),可以正确推断 OP 的程序。
然而,在新的特征引擎实现之前,如果你必须使用borrow
你可以通过告诉编译器什么来帮助编译器X1
应该:
read_exact::<&TcpStream, _>(conn.borrow(), [u8]);
// ^~~~~~~~~~ forces &X1 = &TcpStream
如果您有兴趣,请看以下内容chalk程序证明新的求解器可以对 OP 的示例进行类型检查
trait Borrow<T> {}
trait AsyncRead {}
trait Read {}
struct Ref<T> {} // meaning &T
struct Rc<T> {}
impl<T> Borrow<T> for Rc<T> {}
struct TcpStream {}
impl Read for TcpStream {}
impl AsyncRead for TcpStream {}
impl Read for Ref<TcpStream> {}
impl AsyncRead for Ref<TcpStream> {}
struct PollEvented<E> {}
impl<E> AsyncRead for Ref<PollEvented<E>> where Ref<E>: Read {}
impl<E> Read for Ref<PollEvented<E>> where Ref<E>: Read {}
// Verify:
//
// ?- exists<X> { Ref<X>: AsyncRead, Rc<TcpStream>: Borrow<X> }
// Unique; substitution [?0 := TcpStream], lifetime constraints []