< 返回版块

LongRiver 发表于 2023-08-26 13:34

我要使用HashMap。其中key是一个struct,其中包括了一个String类型(就是非Copy的):

struct Key {
  uid: u64,
  name: String,
}

然后我想定义一个get函数:

fn get(dict: &HashMap, uid: u64, name: &String) -> Option<Value> {
  let key = Key { uid, name };  // <-- name.clone()?
  dict.get(&key)
}

这个函数的最后一个参数,name,我希望是&String而不是String,这样外面的调用者就不用消耗掉这个name。

然后问题就来了,在函数内部定义这个临时的key变量时,这个name怎么处理?难道要clone()吗?这个代价就太高了。

请问下,这种需求,应该怎么处理?

评论区

写评论
作者 LongRiver 2023-08-28 10:06

但是在构造Key的时候,还行需要消耗String的。见上面代码里 加注释的那行。

--
👇
bestgopher: get函数传入Key的引用就行了呀,这样就不会消耗String了

bestgopher 2023-08-28 09:34

get函数传入Key的引用就行了呀,这样就不会消耗String了

作者 LongRiver 2023-08-26 19:06

高级!

相对我的小项目,引入这个有点小题大做了。

希望以后标准库能引入这个功能吧。

--
👇
hangj: 不管我们定义的 Key 是什么样的 struct,HashMap 底层数据结构中的 key 就是一个 u64,HashMap 最终是通过这个 u64 来查找 value 的

但是标准库并没有提供一个 pub fn get(k: u64) -> Option<&V> 这样的接口

为了添加这样一个接口,这个哥们儿自己实现了一个 struct DualKeyHashMap, 就要为了加上下面这个函数:

pub fn get2<M>(&self, k: &M) -> Option<&V>
    where
        M: AlternateKey<K>,
    {
        let hash = make_hash::<M, M, S>(&self.hash_builder, k);
        match self
            .base
            .get(hash, |(k2, _)| <M as AlternateKey<K>>::eq(k, &k2))
        {
            Some(&(_, ref v)) => Some(v),
            None => None,
        }
    }

你看下:

playground

hangj 2023-08-26 18:21

不管我们定义的 Key 是什么样的 struct,HashMap 底层数据结构中的 key 就是一个 u64,HashMap 最终是通过这个 u64 来查找 value 的

但是标准库并没有提供一个 pub fn get(k: u64) -> Option<&V> 这样的接口

为了添加这样一个接口,这个哥们儿自己实现了一个 struct DualKeyHashMap, 就要为了加上下面这个函数:

pub fn get2<M>(&self, k: &M) -> Option<&V>
    where
        M: AlternateKey<K>,
    {
        let hash = make_hash::<M, M, S>(&self.hash_builder, k);
        match self
            .base
            .get(hash, |(k2, _)| <M as AlternateKey<K>>::eq(k, &k2))
        {
            Some(&(_, ref v)) => Some(v),
            None => None,
        }
    }

你看下:

playground

作者 LongRiver 2023-08-26 16:50

没太看懂。

我理解的是,可以定义一个新的类型,KeyRef,然后实现 Borrow for Key?

但是我看回答里也说了,要确保两个类型的layout一致,这个就不太理解了。

我之前没用过Borrow。看了下 impl Borrow for String 的实现,猜测是需要可以从Key里直接返回KeyRef类型的ref。所以才需要要求两个类型的layout一致。

而我的例子里的Key类型的定义,是不能(?)定义一个相同layout的KeyRef出来的。所以这条路就也不通了?

--
👇
hangj: https://stackoverflow.com/questions/68489227/what-technique-should-i-use-to-create-a-rust-hashmap-composite-key-that-is-hard

hangj 2023-08-26 15:48

https://stackoverflow.com/questions/68489227/what-technique-should-i-use-to-create-a-rust-hashmap-composite-key-that-is-hard

作者 LongRiver 2023-08-26 15:06

搜了下so,里面有个回答说不能: https://stackoverflow.com/a/37830094/4794937 。 不过这个回答的下面说 Rust2018就可以了,但没说具体怎么做。

1 2 共 27 条评论, 2 页