Вот 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
Я хотел бы иметь альтернативу, которая позволила бы мне манипулировать (и получить из) внутренний тип варианта без повсеместных обобщений.
Как предложено в Как можно избежать эффекта пульсации от изменения конкретной структуры на generi c? , если я вместо этого могу использовать 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);
}
детская площадка
Однако, поскольку это больше не enum, я больше не могу создать вариант под одним enum / struct (код выше не компилируется).
С одной стороны, я хочу иметь возможность создать одну единственную структуру / enum, которая содержит несколько сложных типов (enum), но с другой стороны я хочу иметь возможность получить / получить доступ к базовому объекту. Я не могу найти способ сделать обе вещи.