- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试创建一个 DefaultHashMap
结构,它基本上是 HashMap
的包装器,不同之处在于当获取不在映射中的键时默认值被放入该键并返回。
我制作了一个get
和一个get_mut
方法,它工作正常。现在我正在尝试将 Index
和 IndexMut
实现为这些方法的包装器。在这里,我遇到了两个问题。
第一个问题是由于 get
必须在键不存在时改变结构,它需要一个可变引用。但是,Index
的 index
方法的签名有 &self
而不是 &mut self
,所以我无法实现它.
这会导致第二个问题,IndexMut
需要一个Index
实现。因此,即使 IndexMut
的实现没有问题,我也不能这样做,因为 Index
无法实现。
第一个问题很烦人但可以理解。对于第二个,我不明白为什么会有这个要求。我想有办法解决它。现在我正在做以下事情,但我希望有人有更好的解决方案:
impl<K: Eq + Hash, V: Clone> Index<K> for DefaultHashMap<K, V> {
type Output = V;
fn index(&self, _: K) -> &V {
panic!("DefautHashMap doesn't implement indexing without mutating")
}
}
impl<K: Eq + Hash, V: Clone> IndexMut<K> for DefaultHashMap<K, V> {
#[inline]
fn index_mut(&mut self, index: K) -> &mut V {
self.get_mut(index)
}
}
最佳答案
首先,我怀疑您的要求“当获取不在 map 中的键时,将默认值放入该键中”并不是完全必需的!
考虑一个不可变访问 let foo = default_hash_map[bar] + 123;
.除非您打算在 map 中使用具有内部可变性的值,否则 default_hash_map[bar]
是否无关紧要。实际上是在创建一个键或只是返回对单个默认值的引用。
现在,如果您确实需要在访问期间创建新条目,那么有一种方法可以做到这一点。仅允许您添加具有可变访问权限的新条目的借用检查器限制在这里阻止您创建悬空指针,这种悬空指针在您修改 map 时会在其中保存引用时出现。但是,如果您使用的是具有稳定引用的结构,其中稳定意味着当您向结构中输入新条目时引用不会失效,那么借用检查器试图防止的问题就会消失。
在 C++ 中,我会考虑使用 deque当您向其中添加新条目时,标准保证不会使其引用无效。不幸的是,Rust 双端队列是不同的(尽管您可能会找到具有类似于 C++ 双端队列的属性的 arena allocator crates)所以对于这个例子我使用了 Box
.盒装值单独驻留在堆上,当您将新条目添加到 HashMap
时不会移动。 .
现在,您的正常访问模式可能是修改 新条目,然后访问 map 的现有 条目。因此在 Index::index
中创建新条目是一个异常(exception),不应减慢 map 的其余部分。因此,只为 Index::index
支付装箱价格可能是有意义的。使用权。为此,我们可能会使用第二个结构,它只保留盒装的 Index::index
。值(value)观。
知道HashMap<K, Box<V>>
可以在不使现有 V
失效的情况下插入refereces 允许我们将它用作临时缓冲区,保存 Index::index
-创建值,直到我们有机会将它们与主要 HashMap
同步.
use std::borrow::Borrow;
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Index;
use std::ops::IndexMut;
struct DefaultHashMap<K, V>(HashMap<K, V>, UnsafeCell<HashMap<K, Box<V>>>, V);
impl<K, V> DefaultHashMap<K, V>
where K: Eq + Hash
{
fn sync(&mut self) {
let buf_map = unsafe { &mut *self.1.get() };
for (k, v) in buf_map.drain() {
self.0.insert(k, *v);
}
}
}
impl<'a, K, V, Q: ?Sized> Index<&'a Q> for DefaultHashMap<K, V>
where K: Eq + Hash + Clone,
K: Borrow<Q>,
K: From<&'a Q>,
Q: Eq + Hash,
V: Clone
{
type Output = V;
fn index(&self, key: &'a Q) -> &V {
if let Some(v) = self.0.get(key) {
v
} else {
let buf_map: &mut HashMap<K, Box<V>> = unsafe { &mut *self.1.get() };
if !buf_map.contains_key(key) {
buf_map.insert(K::from(key), Box::new(self.2.clone()));
}
&*buf_map.get(key).unwrap()
}
}
}
impl<'a, K, V, Q: ?Sized> IndexMut<&'a Q> for DefaultHashMap<K, V>
where K: Eq + Hash + Clone,
K: Borrow<Q>,
K: From<&'a Q>,
Q: Eq + Hash,
V: Clone
{
fn index_mut(&mut self, key: &'a Q) -> &mut V {
self.sync();
if self.0.contains_key(key) {
self.0.get_mut(key).unwrap()
} else {
self.0.insert(K::from(key), self.2.clone());
self.0.get_mut(key).unwrap()
}
}
}
fn main() {
{
let mut dhm = DefaultHashMap::<String, String>(HashMap::new(),
UnsafeCell::new(HashMap::new()),
"bar".into());
for i in 0..10000 {
dhm[&format!("{}", i % 1000)[..]].push('x')
}
println!("{:?}", dhm.0);
}
{
let mut dhm = DefaultHashMap::<String, String>(HashMap::new(),
UnsafeCell::new(HashMap::new()),
"bar".into());
for i in 0..10000 {
let key = format!("{}", i % 1000);
assert!(dhm[&key].len() >= 3);
dhm[&key[..]].push('x');
}
println!("{:?}", dhm.0);
}
{
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
struct K(u32);
impl<'a> From<&'a u32> for K {
fn from(v: &u32) -> K {
K(*v)
}
}
impl<'a> Borrow<u32> for K {
fn borrow(&self) -> &u32 {
&self.0
}
}
let mut dhm = DefaultHashMap::<K, K>(HashMap::new(),
UnsafeCell::new(HashMap::new()),
K::from(&123));
for i in 0..10000 {
let key = i % 1000;
assert!(dhm[&key].0 >= 123);
dhm[&key].0 += 1;
}
println!("{:?}", dhm.0);
}
}
( playground )
请注意,装箱只会稳定新条目的插入。要删除 盒装条目,您仍然需要对 &mut self
的可变 ( DefaultHashMap
) 访问权限.
关于rust - 只实现 IndexMut 不实现 Index,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43558362/
这个问题已经有答案了: 已关闭14 年前。 ** 重复:What's the difference between X = X++; vs X++;? ** 所以,即使我知道你永远不会在代码中真正做到
我在一本C语言的书上找到了这个例子。此代码转换输入数字基数并将其存储在数组中。 #include int main(void) { const char base_digits[16] =
尝试使用“pdf_dart”库保存 pdf 时遇到问题。 我认为问题与我从互联网下载以尝试附加到 pdf 的图像有关,但我不确定它是什么。 代码 import 'dart:io'; import 'p
我的 Apache 服务器曾经可以正常工作,但它随机开始对几乎每个目录发出 403 错误。两个目录仍然有效,我怎样才能使/srv/www/htdocs 中的所有目录正常工作? 我查看了两个可用目录的权
这些索引到 PHP 数组的方法之间有什么区别(如果有的话): $array[$index] $array["$index"] $array["{$index}"] 我对性能和功能上的差异都感兴趣。 更
我有一个简单的结构,我想为其实现 Index,但作为 Rust 的新手,我在借用检查器方面遇到了很多麻烦。我的结构非常简单,我想让它存储一个开始值和步长值,然后当被 usize 索引时它应该返回 st
我对 MarkLogic 中的 element-range-index 和 field-range-index 感到困惑。 请借助示例来解释差异。 最佳答案 这两个都是标量索引:特定类型的基于值的排序
我对 MarkLogic 中的 element-range-index 和 field-range-index 感到困惑。 请借助示例来解释差异。 最佳答案 这两个都是标量索引:特定类型的基于值的排序
所以我有一个 df,我在其中提取一个值以将其存储在另一个 df 中: import pandas as pd # Create data set d = {'foo':[100, 111, 222],
我有一个由 codeigniter 编写的网站,我已经通过 htaccess 从地址中删除了 index.php RewriteCond $1 !^(index\.php|resources|robo
谁能告诉我这两者有什么区别: ALTER TABLE x1 ADD INDEX(a); ALTER TABLE x1 ADD INDEX(b); 和 ALTER TABLE x1 ADD INDEX(
我在 Firefox 和其他浏览器上遇到嵌套 z-index 的问题,我有一个 div,z-index 为 30000,位于 label 下方> zindex 为 9000。我认为这是由 z-inde
Link to the function image编写了一个函数来查找中枢元素(起始/最低)的索引 排序和旋转数组。我解决了这个问题并正在检查 边缘情况,它甚至适用于索引为零的情况。任何人都可以 解
我正在尝试运行有关成人人口普查数据的示例代码。当我运行这段代码时: X_train, X_test, y_train, y_test = cross_validation.train_test_spl
我最近将我的 index.html 更改为 index.php - 我希望能够进行重定向以反射(reflect)这一点,然后还进行重写以强制 foo.com/index.php 成为 foo.com/
我最近将我的 index.html 更改为 index.php - 我希望能够进行重定向以反射(reflect)这一点,然后还进行重写以强制 foo.com/index.php 成为 foo.com/
我有一个用户定义的函数,如下所示:- def genre(option,option_type,*limit): option_based = rank_data.loc[rank_data[
我有两个巨大的数据框我正在合并它们,但我不想有重复的列,因此我通过减去它们来选择列: cols_to_use=df_fin.columns-df_peers.columns.difference(['
感谢您从现在开始的回答, 我是React Native的新手,我想做一个跨平台的应用所以我创建了index.js: import React from 'react'; import { Co
我知道 not_analyzed 是什么意思。简而言之,该字段不会被指定的分析器标记化。 然而,什么是 NO_NORMS 方法?我看到了文档,但请用简单的英语解释我。什么是索引时间字段和文档提升和字段
我是一名优秀的程序员,十分优秀!