Beginner help to log a hashmap

Hello I started coding rust a few days ago and I'm having issues not every single line, but almost 3 errors per line. And I am stuck for hours to build and even log a simple data structure.

use std::collections::HashMap;

fn main() {

    let mut sys = HashMap::new();
    let mut strategy:HashMap<String, String> = HashMap::new();

    sys.insert("test".to_string(), strategy);

    strategy.insert("hi".to_string(), "yo".to_string());

    for (key, &value) in &sys {
        println!("{}: {:?}", key, value);
    }
}

This code just crashes and I can't seem to print value. I need to print the value. I just want some feedback in the console, just to learn the language. Having the ability to print entire objects would help to look into the std APIs would help.

I'm also trying to create a HashMap with different types inside, which data structure should be used?

Surely not this code, because it doesn't even compile.

If you fix the order of moving strategy and .insert()ing into it, and you stop trying to move out of the value, then it compiles and runs without any issues.

By the way, you can print the entire thing with println!("{:?}", sys); so you don't even need the loop.

None. A HashMap always has one specific key and value type. You can't create a true heterogeneous collection. (There are workarounds with enums or trait objects, though.)

Fortunately, when you think you need a heterogeneous collection, you really don't. Please tell us more about your use case and what higher-level goal you are trying to achieve, so that we can suggest a better solution.

Thank you. I come from JS and hit performance limits although doing multi threading and all other sorts of tricks. Either I study C++ or Rust.

So I'm trying to rewrite my software (~7000 lines of code) in Rust. But first I'm starting with small parts and patterns I would use in JS and see how they would be solved in Rust. Just some very small steps, and it is already very hard.

Is there something like object destructuring?

const { broker } = sys

I use this a lot, almost in every function.

Yes, for example:

struct MyStruct {
    field1: u32,
    field2: u32,
}

fn foo(ms: MyStruct) {
    let MyStruct { field1, field2 } = ms;
}

Here it should be noted that this destroys the struct since the right-hand-side has type MyStruct. You can avoid this by giving the right-hand-side a reference type like this:

struct MyStruct {
    field1: u32,
    field2: u32,
}

fn foo(ms: MyStruct) {
    let MyStruct { field1, field2 } = &ms;
}

When you do this, field1 and field2 become references as well, and they will point inside ms.

Note that this only works for structs, tuples and fixed size arrays. It doesn't work for hash maps.

1 Like

next I would mutate a nested field inside that destructured object?
I guess this would crash my compiler a thousand times.

Thanks for the answer and inspiration really helps me a lot getting into Rust.

If you make the right-hand-side a mutable reference, then the field variables will also become mutable references to the fields. Modifying via those references will modify the struct itself.

I don't know what you mean by crashing your compiler.

You can bind a mutable reference to any field in destructuring, too. Continuing Alice's example:

struct MyStruct {
    field1: u32,
    field2: u32,
}

fn foo(mut ms: MyStruct) {
    let MyStruct { ref mut field1, ref mut field2 } = ms;
    *field1 = 1;
    *field2 = 2;
}

or something like that.

Since you mention nested fields, here's an example of a nested struct.

struct MyStruct {
    field1: u32,
    field2: MyInnerStruct,
}

struct MyInnerStruct {
    field3: u32,
}

fn foo(ms: MyStruct) {
    let MyStruct { field1, field2: MyInnerStruct { field3 } } = ms;
}

The left-hand-side of a let statement can be any irrefutable pattern.

Please be adviced that the example by @H2CO3 uses an old syntax (the ref keyword) rather than the syntax I tried to explain in my examples. With my example, you make the right-hand-side a reference, which turns the fields into references of the same type. This feature is called match ergonomics. The older way of doing things (back then, you couldn't use a reference as the right-hand-side) uses a special keyword called ref instead. The ref keyword is not necessary anymore, and I recommend sticking to one way of doing things — I prefer the new way.

And, to defend the "old" way, which I prefer: binding a value type to a reference, and then having its value-typed fields turned into references seems inconsistent. If you were to write out the types explicitly in

let MyStruct { field1, field2 } = &ms;

then ms has type MyStruct, therefore &ms has type &MyStruct (a reference). The left-hand-side pattern, however, has type MyStruct (i.e., the value type itself, not a reference to it), so it looks like the types don't match. Binding like this, however, performs several dereferencing and referencing operators implicitly, and it has caused non-trivial amounts of confusion (you can search this forum for the aforementioned "match ergonomics" expression to see real examples).

I usually do not care to discuss the topic of which option is best. I brought it up here because I had just explained that the right-hand-side should be a reference, so an example where it is not is bound to cause confusion.