Reputation: 1402
I want to define a HashMap
with a key type of String
and the value type is itself.
I tried to write something like:
HashMap<String, HashMap<String, ...>>
I found this requires recursion and I don't know how to write recursion in a type.
After reading Recursive generic types, I tried:
type HashToHash = HashMap<String, HashToHash>
However I got error:
error[E0391]: cycle detected when processing `HashToHash`
--> src/lib.rs:3:35
|
3 | type HashToHash = HashMap<String, HashToHash>;
| ^^^^^^^^^^
|
= note: ...which again requires processing `HashToHash`, completing the cycle
Is there a way to define this kind of type in Rust?
Upvotes: 6
Views: 2487
Reputation: 11397
From comments:
use std::collections::HashMap;
struct HashToHash(HashMap<String, HashToHash>);
fn main() {
let mut h = HashToHash(HashMap::new());
h.0.insert("gloink".to_owned(), HashToHash(HashMap::new()));
}
Reference to original comments: 1 2
Upvotes: 3
Reputation: 177
The compiler is trying to tell you that you are about to define an infinite type. The reason for your mistake is that generics in C# and Java are ∀-polymorphic, i.e. one implementation exists for all parameters. Rust is λ-polymorphic, i.e. for each parameter an implementation is created (and optimized). This is what is usually called a template and you might know it from C++. If Rust developers of the early days would have had more experience, a lot of concepts in Rust would be known under different names. Generics is just one of it.
The only way to resort from the infinite loop is to use some sort of pointer to the type you define on your RHS.
Honstly, I found this question because I wanted to know if Rust can predeclare a template and use pointers to it without knowing the definition. As I did not find any documentation on the topic, the answer is likely no.
If you really need this, you can, in any λ-polymorphic language, resort to an untyped pointer to break the recursion. Doing so, you should wrap all data access behind an API.
Upvotes: 4