以下是两个未编译的示例:
type Common<K, V> = HashMap<K, V>;
type Variant1 = Common<u32, u64>;
type Variant2 = Common<i32, i64>;
enum Stuff {
V1(Variant1),
V2(Variant2),
}
impl Stuff {
fn new(variant1: bool) -> Stuff {
if variant1 {
Stuff::V1(Variant1::new())
} else {
Stuff::V2(Variant2::new())
}
}
// Example 1
fn get<K, V>(&self) -> &Common<K, V> {
match self {
Stuff::V1(x) => x,
Stuff::V2(x) => x,
}
}
// Example 2
fn get_key<K, V>(&self, key: K) -> Option<&V> {
match self {
Stuff::V1(x) => x.get(key),
Stuff::V1(x) => x.get(key),
}
}
}
playground
error[E0308]: mismatched types
--> src/main.rs:23:29
|
21 | fn get<K, V>(&self) -> &Common<K, V> {
| - this type parameter
22 | match self {
23 | Stuff::V1(x) => x,
| ^ expected type parameter `K`, found `u32`
|
= note: expected reference `&std::collections::HashMap<K, V>`
found reference `&std::collections::HashMap<u32, u64>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0308]: mismatched types
--> src/main.rs:30:35
|
28 | fn get_key<K, V>(&self, key: K) -> &V {
| - this type parameter
29 | match self {
30 | Stuff::V1(x) => x.get(key),
| ^^^ expected `&u32`, found type parameter `K`
|
= note: expected reference `&u32`
found type parameter `K`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0308]: mismatched types
--> src/main.rs:30:29
|
30 | Stuff::V1(x) => x.get(key),
| ^^^^^^^^^^ expected `&V`, found enum `std::option::Option`
|
= note: expected reference `&V`
found enum `std::option::Option<&u64>`
error[E0308]: mismatched types
--> src/main.rs:31:35
|
28 | fn get_key<K, V>(&self, key: K) -> &V {
| - this type parameter
...
31 | Stuff::V1(x) => x.get(key),
| ^^^ expected `&u32`, found type parameter `K`
|
= note: expected reference `&u32`
found type parameter `K`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
我想有一个替代方法,使我可以在不使用泛型的情况下操纵变量的内部类型(并从中获取信息)。
如How can I avoid a ripple effect from changing a concrete struct to generic?中的建议,如果我可以将
Box
与结构一起使用,则它可以正常工作:use std::collections::HashMap;
trait Common<K, V> {
fn get(&self, key: &K) -> Option<&V>;
}
struct Variant1(HashMap<u32, u64>);
struct Variant2(HashMap<i32, i64>);
impl Common<u32, u64> for Variant1 {
fn get(&self, key: &u32) -> Option<&u64> {
self.get(key)
}
}
impl Common<i32, i64> for Variant2 {
fn get(&self, key: &i32) -> Option<&i64> {
self.get(key)
}
}
struct Stuff<K, V>(Box<dyn Common<K, V>>);
impl<K, V> Stuff<K, V> {
fn new(variant1: bool) -> Stuff<K, V> {
if variant1 {
Stuff(Box::new(Variant1(HashMap::new())))
} else {
Stuff(Box::new(Variant2(HashMap::new())))
}
}
}
impl<K, V> Common<K, V> for Stuff<K, V> {
fn get(&self, key: &K) -> Option<&V> {
self.0.get(key)
}
}
fn main() {
let stuff1 = Stuff::new(true);
let r1 = stuff1.get(&42);
let stuff2 = Stuff::new(true);
let r2 = stuff2.get(&42);
}
playground
但是,因为它不再是枚举,所以我不能再在一个枚举/结构下创建变体(上面的代码无法编译)。
一方面,我希望能够创建一个包含多个复杂类型(枚举)的结构/枚举,但是另一方面,我希望能够获取/访问基础对象。我找不到做这两种事情的方法。
最佳答案
HashMap<u32, u64> != HashMap<i32, i64>
我知道键和值类型的大小是相同的,因此内存中的表示形式将相似,但是如果不使用不安全的,rust将不允许您在这两种类型之间进行回退和第四次转换。
以下示例不使用不安全的方法。
您应该注意,此线程中的示例在逻辑上并不合理,因为在有符号和无符号整数之间进行强制转换会产生错误的结果。
use std::collections::HashMap;
struct Stuff {
map: HashMap<[u8; 4], [u8; 8]>,
}
impl Stuff {
fn new() -> Stuff {
Stuff {
map: HashMap::new(),
}
}
fn get_u32_u64(&self, key: u32) -> Option<u64> {
self.map
.get(&key.to_ne_bytes())
.cloned()
.map(u64::from_ne_bytes)
}
fn get_i32_u64(&self, key: i32) -> Option<u64> {
self.map
.get(&key.to_ne_bytes())
.cloned()
.map(u64::from_ne_bytes)
}
fn get_u32_i64(&self, key: u32) -> Option<i64> {
self.map
.get(&key.to_ne_bytes())
.cloned()
.map(i64::from_ne_bytes)
}
fn get_i32_i64(&self, key: i32) -> Option<i64> {
self.map
.get(&key.to_ne_bytes())
.cloned()
.map(i64::from_ne_bytes)
}
}
这是使用特征的另一种选择。
use std::collections::HashMap;
struct Stuff {
map: HashMap<[u8; 4], [u8; 8]>,
}
trait StuffKey {
fn key(self) -> [u8; 4];
}
trait StuffValue {
fn val(val: [u8; 8]) -> Self;
}
impl Stuff {
fn new() -> Stuff {
Stuff {
map: HashMap::new(),
}
}
fn get<K: StuffKey, V: StuffValue>(&self, key: K) -> Option<V> {
self.map.get(&key.key()).cloned().map(StuffValue::val)
}
}
impl StuffKey for i32 {
fn key(self) -> [u8; 4] {
self.to_ne_bytes()
}
}
impl StuffKey for u32 {
fn key(self) -> [u8; 4] {
self.to_ne_bytes()
}
}
impl StuffValue for i64 {
fn val(val: [u8; 8]) -> Self {
Self::from_ne_bytes(val)
}
}
impl StuffValue for u64 {
fn val(val: [u8; 8]) -> Self {
Self::from_ne_bytes(val)
}
}
关于rust - 如何从枚举返回内部类型变量引用而又没有遍历泛型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60231809/