Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
675 views
in Technique[技术] by (71.8m points)

rust - How to use a struct's member as its own key when inserting the struct into a map without duplicating it?

Is it possible to insert a struct into a map where the key is owned by the value being inserted?

When using hash-maps in C, this is something which I'm used to doing.

Pseudocode example:

struct MyStruct {
    pub map: BTreeMap<&String, StructThatContainsString>,
    // XXX            ^ Rust wants lifetime specified here!
}

struct StructThatContainsString {
    id: String,
    other_data: u32,
}

fn my_fn() {
    let ms = MyStruct { map: BTreeMap::new() };

    let item = StructThatContainsString {
        id: "Some Key".to_string(),
        other_data: 0,
    }

    ms.insert(&item.id, item);
}

How can this situation be correctly handled?


  • If this isn't possible, could the reverse be done, where the value holds a reference to the key which would be a String ?

  • An alternative could be to use a set instead of a map, then store the entire struct as the key, but only use one of its values when comparing (seems like it would work, but could backfire if you wanted to compare the struct in other contexts).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not going to work with plain references:

let item = StructThatContainsString {
    id: "Some Key".to_string(),
    other_data: 0,
}

ms.insert(&item.id, item);

item is moved into the map, so there can't be any pending borrows/references.

Also, methods like get_mut() would become dangerous or impossible, as it would let you modify the item that has an outstanding reference.

Assuming the reason for wanting to do this is to save space, the obvious options are:

  • Take the key out of the value struct. If you need it at the same time, you've either got it when looking up a key in the map, or the iterators include both key and value:

    struct OnlyKey {
        id: String,
    }
    
    struct OnlyValue {
        other_data: u32,
    }
    

    This can be cleaned up with appropriate methods to split apart / recombine the various pieces.

  • Use something like Rc for the key part of the value. Rc<T> implements Ord (required for BTreeMap) if T does.

    struct StructThatContainsString {
        id: Rc<String>,
        other_data: u32,
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...