[英]How to return an inner type variant reference from an enum without having generics all over the place?
以下是 2 个无法编译的示例:
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),
}
}
}
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
我想要一个替代方案,让我可以操纵(并从中获取)变体的内部类型,而无需到处都有泛型。
正如我如何避免将具体结构更改为通用结构所产生的连锁反应所建议的那样? ,如果我可以使用带有结构的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);
}
然而,因为这不再是一个枚举,我不能再在一个枚举/结构下创建变体(上面的代码不能编译)。
一方面,我希望能够创建一个包含多个复杂类型(枚举)的单个结构/枚举,但另一方面我希望能够获取/访问底层对象。 我找不到同时做这两件事的方法。
HashMap<u32, u64> != HashMap<i32, i64>
我知道键和值类型的大小相同,因此内存中的表示形式将是相似的,但是 rust 不会让您在不使用unsafe 的情况下在这两种类型之间进行转换。
下面的例子没有使用 unsafe。
您应该注意,此线程中的示例在逻辑上不合理,因为在有符号和无符号整数之间进行转换会产生不正确的结果。
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)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.