虽然以前的答案解释了how的长度,但他们没有解释why是如何工作的.我将try 解释后一种机制,以便您在将来了解此机制.
由于Deref
特性和deref coercion特性,可以在"外部"对象上调用"内部"对象的方法.
Deref
特征定义了取消引用运算符*
的语义.例如,当您取消引用String
时,您将获得str
,当您取消对Vec<T>
的引用时,您将获得[T]
.同样,像Box<T>
或Arc<T>
这样的智能指针在您取消引用它们时会得到T
.
可以手动执行此取消引用操作:
let map = Arc::new(RwLock::new(HashMap::from([("a", "b"), ("c", "d")])));
let len = (&*(&*map).read().await).len();
然而,这很快就会变得非常混乱.幸运的是,deref coercion提供了帮助,并自动魔术地执行了这一系列的取消引用.在链接的文档中描述了它如何工作的详细信息,但它的要点是,当您对对象bar: Bar
调用方法foo
时,编译器将执行以下操作:
- 判断
Bar
是否有方法foo
,如果没有,则
- 判断
Bar
是否执行Deref<Target=Baz>
,如果执行,则
- 判断
Baz
是否有方法foo
,如果没有,则
- 对之前的
Deref
Target
转换执行步骤2和3,直到它找到实现方法foo
的类型
所以当你写下
let len = map.read().await.len();
编译器执行以下操作:
- 判断
Arc<RwLock<_>>
上的方法read
,但未找到它.
- try 取消对它的引用,并判断
RwLock<_>
上的方法read
.
- 它会找到它,在
await
次搜索结果之后,你会得到RwLockReadGuard<'_, HashMap<_, _>>
.
- 它在
RwLockReadGuard<_>
上查找方法len
,但没有找到.
- 所以它再一次取消对它的引用,结果是
HashMap<_>
.
- 最后,编译器找到实现
len
方法的类型,因此它调用它.