0

I have read those two similar questions here and here. But still can't figure out how to achieve what I want: initializing a String field in a struct with a String that belongs to a HashMap in the same structure. Here is my initial code:

use std::collections::HashMap;

struct S<'a> {
    a: HashMap<String,Vec<String>>,
    b: &'a String,
}

impl <'a> S<'a> {
    fn new() -> S<'a> {
        let mut v:Vec<String> = Vec::new();
        v.push("a".to_string());
        v.push("b".to_string());
        let mut h = HashMap::new();
        h.insert("toto".to_string(),v);
        let b = &h.get("toto").unwrap()[0];
        S {
            a: h,           // error[E0505]: cannot move out of `h` because it is borrowed
            b: b            // error[E0515]: cannot return value referencing local variable `h`
        }
    }
}
fn main() {
    let mut s = S::new();
    println!("s.b = {}", s.b);
}

I would like b to be initilaized with a String value that belong to the HashMap a. Since the above did not work, I tried to initialize b with an empty String, and immediatly change b's value after creating s:

use std::collections::HashMap;

struct S {
    a: HashMap<String,Vec<String>>,
    b: String,
}

impl S {
    fn new() -> S {
        let mut v:Vec<String> = Vec::new();
        v.push("a".to_string());
        v.push("b".to_string());
        let mut h = HashMap::new();
        h.insert("toto".to_string(),v);
        let b = "".to_string();
        S {
            a: h,
            b: b
        }
    }
}
fn main() {
    let mut s = S::new();
    s.b = s.a.get("toto").unwrap()[0];  //error[E0507]: cannot move out of index of `Vec<String>`
    println!("s.b = {}", s.b);
}

Since I cannot copy the value into s.b:

    error[E0507]: cannot move out of index of `Vec<String>`
      --> src/main.rs:24:15
       |
    24 |         s.b = s.a.get("toto").unwrap()[0];  //error[E0507]: cannot move out of index of `Vec<String>`
       |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.

I thought that a reference could work:

use std::collections::HashMap;

struct S<'a> {
    a: HashMap<String,Vec<String>>,
    b: &'a String,
}

impl <'a> S<'a> {
    fn new() -> S<'a> {
        let mut v:Vec<String> = Vec::new();
        v.push("a".to_string());
        v.push("b".to_string());
        let mut h = HashMap::new();
        h.insert("toto".to_string(),v);
        let b = &"".to_string();
        S {
            a: h,
            b: b        // error[E0515]: cannot return value referencing temporary value
        }
    }
}
fn main() {
    let mut s = S::new();
    s.b = &s.a.get("toto").unwrap()[0];  
    println!("s.b = {}", s.b);
}

But of course, I run into the same issue of referencing a value that does not have a lifetime longer than the function. No clue how/if I can tell the compiler that my empty String should live as long as S.

There might be an obvious solution, but if so, I can't see it :-(

0

1 Answer 1

1

There might be an obvious solution, but if so, I can't see it :-(

If your goal is to share the value between the map and the field, then no. Rust does not like self-referential data structures.

And a string is affine, you can't have both the structure and the nested map own the "same" string unless:

  • you relax the ownership using Rc or Arc
  • you clone() the string and both just have a copy of the same thing

There are also crates for string caching / interning, but I've no idea how convenient & efficient they are.

Sign up to request clarification or add additional context in comments.

1 Comment

Indeed, I want my String to point to an element in the HashMap (it's actually the SLD2 Surface I'll need to display at any given point in time. I thought about clone(), but did not like the idea of "duplicating" a Surface that contains an image. I will explore the other suggestions, which I'm not familiar with. Thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.