实施借用回避背后的东西?
我的项目中有structs value 和 repvalue 。 repvalue 是一种参考计数,动态借出的 value 。现在, value 可能包含一个refvalue的哈希图,其中键和值都是refvalue。
type ValueMap = HashMap<RefValue, RefValue>;
#[derive(Debug, PartialEq, Eq)]
enum Value {
Integer(i64),
String(String),
Map(ValueMap),
}
#[derive(Debug, PartialEq, Eq)]
struct RefValue {
value: Rc<RefCell<Value>>,
}
我已经独自在repvalue上实现了哈希,在此 Playground 。
我想实现的是这样的主要程序:
fn main() {
// Simple values
let x = RefValue::from(42);
let y = RefValue::from("Hello");
// Make a map from these values
let mut z = ValueMap::new();
z.insert(RefValue::from("x"), x);
z.insert(RefValue::from("y"), y);
// Make a value from the map
let z = RefValue::from(z);
println!("z = {:?}", z);
// Try to access "x"
if let Value::Map(m) = &*z.borrow() {
println!("m[x] = {:?}", m["x"]); // <- here I want to access by &str
};
}
不幸的是,我会在操场上的评论中找到奇怪的结果。我也不确定是否没有更好地实现整个问题,因为重弹性无法返回其包含元素的借来的值。
有人可以给我提示吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
实现
借用&lt; t&gt;
,hash
实现必须返回与t
s相同的哈希值,以便何时基础值等于。也就是说,如果x.hash()
必须等于x.borrow()。hash()
。Hashmap
索引到其中时依赖于此属性:它需要idx:borrow&lt; key&gt;
,然后使用此规则来确保它可以找到值。您的
impl borrow&lt; str&gt;对于repvalue
不遵循此规则。Refvalue :: Hash()
forrefvalue :: String
调用write_u8(2)
hashing handing string。由于您违反了合同,因此允许hashmap做任何事情(不确定的行为),例如惊慌,流产或找不到钥匙,在这种情况下,这就是它的作用。为了解决这个问题,您不应该放弃判别物(也将其从其他判别中删除,以保持一致性):
现在它在您的
borrow
实施中感到恐慌(但是您不应实现
借用
,因为实现它意味着您的价值是借用价值的反映。Refvalue
绝不是str
。它也可以是整数或地图。因此,您不应为任何一个实现借用
。您可以实现borrow&lt; value&gt;
,但这是不可能的代码>命令返回参考。你不幸。您唯一的选择是用refvalue
s索引。最后,您应该避免钥匙内部的内部可变性。一旦更改它们,很容易通过错误地更改它们,并且您的哈希/平等更改,您将再次与地图违反了合同。
When you implement
Borrow<T>
, yourHash
implementation must return the same hash value asT
's for when the underlying value is equivalent. That is, ifx.hash()
must be equal tox.borrow().hash()
.HashMap
relies on this property when you index into it: it requiresIdx: Borrow<Key>
and then uses this rule to ensure it can find the value.Your
impl Borrow<str> for RefValue
does not follow this rule.RefValue::hash()
forRefValue::String
callswrite_u8(2)
before hashing the string. Since you broke the contract, the hashmap is allowed to do anything (excluding undefined behavior), like panicking, aborting the process, or not finding your key, which is what it does in this case.To fix that, you should just not hash the discriminant (removed it from the others too, for consistency):
Now it panics in your
Borrow
implementation, like you expected (playground).But you should not implement
Borrow
, since implementing it means your value is a reflection of the borrowed value.RefValue
is by no meansstr
. It can be integers, or maps, too. Thus, you should not implementBorrow
for any of those. You could implementBorrow<Value>
, but this is impossible because you useRefCell
and thus need to returnRef
butBorrow
mandates returning a reference. You're out of luck. Your only option is to index withRefValue
s.Lastly, you should avoid interior mutability in keys. Once change them, and it's easy to change them by mistake, and your hash/equality change, you broke your contract with the map once again.