使用泛型取消引用强制
Deref coercion with generics
我正在尝试编写一个参数化函数 if_found_update
来更新散列中的值(如果它存在):
use std::collections::HashMap;
fn if_found_update<K, V>(data: &mut HashMap<K, V>, k: &K, v: &V, f: &Fn(&V, &V) -> V) -> bool
where K: std::cmp::Eq,
K: std::hash::Hash
{
if let Some(e) = data.get_mut(k) {
*e = f(e, v);
return true;
}
false
}
fn main() {
let mut h: HashMap<String, i64> = HashMap::new();
h.insert("A".to_string(), 0);
let one = 1 as i64;
fn update(e1: &i64, e2: &i64) -> i64 {
e1 + e2
};
let k: &str = &"A".to_string();
println!("{}",
if_found_update(&mut h, &"A".to_string(), &one, &update)); // works
println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile
}
if_found_update(&mut h, &"A".to_string(), &one, &update);
工作正常,但 if_found_update(&mut h, k, &one, &update)
编译失败:
error[E0308]: mismatched types
--> src/main.rs:24:44
|
24 | println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile
| ^ expected struct `std::string::String`, found str
|
= note: expected type `&std::string::String`
= note: found type `&str`
我认为这是因为它无法进行适当的 deref 强制转换。有没有办法让这样的东西工作?
HashMap
's methods, i.e. get
, contains_key
, get_mut
and remove
, can receive a borrowed version of the key type. They do this by using the Borrow
trait. They are generic over a type parameter Q
that can be any type that can represent a borrow of a key. It works this way: when X
implements Borrow<Y>
, it means that an &X
can be borrowed as a &Y
. For example, String
implements Borrow<str>
的一部分,所以&String
可以借为&str
。
您可以通过在函数中引入额外的类型参数并添加正确的边界来利用这一点。
use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
fn if_found_update<K, V, Q>(data: &mut HashMap<K, V>, k: &Q, v: &V, f: &Fn(&V, &V) -> V) -> bool
where K: Hash + Eq + Borrow<Q>,
Q: ?Sized + Hash + Eq
{
if let Some(e) = data.get_mut(k) {
*e = f(e, v);
return true;
}
false
}
fn main() {
let mut h: HashMap<String, i64> = HashMap::new();
h.insert("A".to_string(), 0);
let one = 1 as i64;
fn update(e1: &i64, e2: &i64) -> i64 { e1 + e2 }
let k: &str = "A";
println!("{}", if_found_update(&mut h, &"A".to_string(), &one, &update));
println!("{}", if_found_update(&mut h, k, &one, &update));
}
我正在尝试编写一个参数化函数 if_found_update
来更新散列中的值(如果它存在):
use std::collections::HashMap;
fn if_found_update<K, V>(data: &mut HashMap<K, V>, k: &K, v: &V, f: &Fn(&V, &V) -> V) -> bool
where K: std::cmp::Eq,
K: std::hash::Hash
{
if let Some(e) = data.get_mut(k) {
*e = f(e, v);
return true;
}
false
}
fn main() {
let mut h: HashMap<String, i64> = HashMap::new();
h.insert("A".to_string(), 0);
let one = 1 as i64;
fn update(e1: &i64, e2: &i64) -> i64 {
e1 + e2
};
let k: &str = &"A".to_string();
println!("{}",
if_found_update(&mut h, &"A".to_string(), &one, &update)); // works
println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile
}
if_found_update(&mut h, &"A".to_string(), &one, &update);
工作正常,但 if_found_update(&mut h, k, &one, &update)
编译失败:
error[E0308]: mismatched types
--> src/main.rs:24:44
|
24 | println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile
| ^ expected struct `std::string::String`, found str
|
= note: expected type `&std::string::String`
= note: found type `&str`
我认为这是因为它无法进行适当的 deref 强制转换。有没有办法让这样的东西工作?
HashMap
's methods, i.e. get
, contains_key
, get_mut
and remove
, can receive a borrowed version of the key type. They do this by using the Borrow
trait. They are generic over a type parameter Q
that can be any type that can represent a borrow of a key. It works this way: when X
implements Borrow<Y>
, it means that an &X
can be borrowed as a &Y
. For example, String
implements Borrow<str>
的一部分,所以&String
可以借为&str
。
您可以通过在函数中引入额外的类型参数并添加正确的边界来利用这一点。
use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
fn if_found_update<K, V, Q>(data: &mut HashMap<K, V>, k: &Q, v: &V, f: &Fn(&V, &V) -> V) -> bool
where K: Hash + Eq + Borrow<Q>,
Q: ?Sized + Hash + Eq
{
if let Some(e) = data.get_mut(k) {
*e = f(e, v);
return true;
}
false
}
fn main() {
let mut h: HashMap<String, i64> = HashMap::new();
h.insert("A".to_string(), 0);
let one = 1 as i64;
fn update(e1: &i64, e2: &i64) -> i64 { e1 + e2 }
let k: &str = "A";
println!("{}", if_found_update(&mut h, &"A".to_string(), &one, &update));
println!("{}", if_found_update(&mut h, k, &one, &update));
}