我有一个简单的 struct ,其中一个问题变量定义如下:

struct Store {
    questions: Arc<RwLock<HashMap<QuestionId, Question>>>,
}
  • HashMap<QuestionId, Question>-100
  • RwLock<>-100
  • Arc<>-100

抱歉,如果这是一个原始的问题,但:

How can I get the length of the 100 that is wrapped in 101 and 102?

我似乎在Arc文档中也找不到任何东西(尽管我知道它不负责这样的任务).

在某些情况下,这是一个旨在由使用Tokio框架实现的rest API Web服务器使用的存储.

推荐答案

虽然以前的答案解释了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时,编译器将执行以下操作:

  1. 判断Bar是否有方法foo,如果没有,则
  2. 判断Bar是否执行Deref<Target=Baz>,如果执行,则
  3. 判断Baz是否有方法foo,如果没有,则
  4. 对之前的Deref Target转换执行步骤2和3,直到它找到实现方法foo的类型

所以当你写下

let len = map.read().await.len();

编译器执行以下操作:

  1. 判断Arc<RwLock<_>>上的方法read,但未找到它.
  2. try 取消对它的引用,并判断RwLock<_>上的方法read.
  3. 它会找到它,在await次搜索结果之后,你会得到RwLockReadGuard<'_, HashMap<_, _>>.
  4. 它在RwLockReadGuard<_>上查找方法len,但没有找到.
  5. 所以它再一次取消对它的引用,结果是HashMap<_>.
  6. 最后,编译器找到实现len方法的类型,因此它调用它.

Rust相关问答推荐

如何在rust中有条件地分配变量?

Rust:跨多个线程使用hashmap Arc和rwlock

在UdpSocket上使用sendto时的隐式套接字绑定

将数组转换为HashMap的更简单方法

无符号整数的Rust带符号差

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

我们能确定Rust会优化掉Clone()吗?如果它会立即掉落?

是否提供Bundle 在可执行文件中的warp中的静态文件?

Const 上下文:从 init 函数创建具有 const 通用长度的数组

try 从标准输入获取用户名和密码并删除 \r\n

如何将 &[T] 或 Vec<T> 转换为 Arc<Mutex<[T]>>?

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

trait 对象指针的生命周期

在 Rust 中实现资源消耗的安全包装器

在构建器模式中捕获 &str 时如何使用生命周期?

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

试图理解 Rust 中的可变闭包

具有生命周期和以后引用的可变方法

有没有更好的方法来为拥有 DIsplay 事物集合的 struct 实现 Display?

有没有比多个 push_str() 调用更好的方法将字符串链接在一起?