我试图学习Rust,但我在使用不同的智能指针时遇到了一些问题.

这是我的代码:

pub struct MyMap<T> {
    map: Rc<RefCell<HashMap<String, T>>>,
}

impl <T> MyMap<T> {
    // Not entire sure if it's supposed to be Option<Ref<T>> or something else here.
    pub fn get(&self, key: &str) -> Option<Ref<T>> {
        todo!("What do I do here?")
    }
}

我找到的最接近的方法是搜索HashMap两次:

impl <T> MyMap<T> {
    pub fn get(&self, key: &str) -> Option<Ref<T>> {
        if self.map.borrow().contains_key(key) {
            Some(Ref::map(self.map.borrow(), |m| m.get(key).unwrap()))
        } else {
            None
        }
    }
}

至少可以说这不是很优雅.

推荐答案

我想到了两个解决方案:

  • 使用不稳定Ref::filter_map,它可能在1.63.0中稳定.
  • 使用上下文管理器模式,可以避免整个问题.

filter_map:

#![feature(cell_filter_map)]

use std::{
    cell::{Ref, RefCell},
    collections::HashMap,
    rc::Rc,
};

pub struct MyMap<T> {
    map: Rc<RefCell<HashMap<String, T>>>,
}

impl<T> MyMap<T> {
    pub fn get(&self, key: &str) -> Option<Ref<T>> {
        Ref::filter_map(self.map.borrow(), |map| map.get(key)).ok()
    }
}

fn main() {
    let map: MyMap<u32> = MyMap {
        map: Rc::new(RefCell::new(HashMap::from([
            ("meaning".to_string(), 42),
            ("nice".to_string(), 69),
        ]))),
    };

    println!("{:?}", map.get("meaning"));
}
Some(42)

上下文管理器:

这里的 idea 是,不是返回引用,而是传递需要值的操作的闭包.这完全避免了生存期问题,因为在执行闭包时,get(或下面示例中的with_value)中的变量仍在范围内.

use std::{cell::RefCell, collections::HashMap, rc::Rc};

pub struct MyMap<T> {
    map: Rc<RefCell<HashMap<String, T>>>,
}

impl<T> MyMap<T> {
    pub fn with_value<F, O>(&self, key: &str, f: F) -> O
    where
        F: FnOnce(Option<&T>) -> O,
    {
        f(self.map.borrow().get(key))
    }
}

fn main() {
    let map: MyMap<u32> = MyMap {
        map: Rc::new(RefCell::new(HashMap::from([
            ("meaning".to_string(), 42),
            ("nice".to_string(), 69),
        ]))),
    };

    map.with_value("meaning", |value| {
        println!("{:?}", value);
    });
}
Some(42)

Rust相关问答推荐

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

把Vector3变成Vector4的绝妙方法

trait声明中的生命周期参数

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

rust 迹-内存管理-POP所有权-链表

从Type::new()调用函数

铁 rust 中的共享对象实现特征

原始数组数据类型的默认trait实现

在Rust中判断编译时是否无法访问

写入引用会更新基础值,但引用会打印意外的值

为什么AsyncRead在Box上的实现有一个Unpin特征绑定?

Rust面向对象设计模式

如何重命名 clap_derive 中的子命令占位符?

我可以用 Rust 编写一个不可变变量

有没有办法通过命令获取 Rust crate 的可安装版本列表?

从嵌入式 Rust 中的某个时刻开始经过的时间

在线程中运行时,TCPListener(服务器)在 ip 列表中的服务器实例之前没有从客户端接受所有客户端的请求

在异步 Rust 中,Future 如何确保它只调用最近的 Waker?

使用 `.` 将 T 转换为 &mut T?

在同一向量 Rust 中用另一个字符串扩展一个字符串