在循环中引用集合项时,装箱或显式生命周期是正确的解决方案吗?

Is boxing or explicit lifetimes the right solution when referencing a collection item in a loop?

在 Rust(版本 1.x)中,我想在循环中使用集合的元素,例如示例 下面(记录它看到的字符并在发现重复字符时执行某些操作)其中集合在函数内部定义并且仅由循环使用。

    fn do_something(word:&str) -> u32 {
            let mut seen_chars = HashMap::new();
            let mut answer : u32 = 0;
            for (i,c) in word.chars().enumerate() {
            let char_str = Box::new(c.to_string());
            match seen_chars.get(&char_str) {
                    Some(&index) => {
                    answer = answer + index;
                    },
                    None => {seen_chars.insert(char_str,i);}
            }; 

    }
    answer
    }

为了在我的 hashmap 中存储对 c 的引用(我已在循环外声明),我需要将 c 框 并将其分配在堆上。这感觉效率低下,好像我一定做错了什么。 我想知道使用显式生命周期是否是一种更好的做事方式,下面是我最好的尝试,但我无法编译它。

    fn do_something<'a>(word:&str) -> u32 {
            let mut seen_chars = : &'a HashMap<&str,usize> = &HashMap::new();
            let mut answer : u32 = 0;
            for (i,c) in word.chars().enumerate() {
            let char_str =  &'a str = &c.to_string();
            match seen_chars.get(&char_str) {
                    Some(&index) => {
                    answer = answer + index;
                    },
                    None => {seen_chars.insert(char_str,i);}
            }; 

    }
    answer
    }

当我尝试编译时,我得到 "error: borrowed value does not live long enough" 并指示“&HashMap::new()”是问题所在。 我可以使用生命周期规范来解决这个问题还是我做错了?

我认为您的任何一种方法都不是最佳解决方案。您可以只使用 char 本身作为 HashMap 的键,无需将其转换为 String:

fn do_something(word:&str) -> usize {
    let mut seen_chars = HashMap::new();
    let mut answer : usize = 0;
    for (i,c) in word.chars().enumerate() {
        match seen_chars.get(&c) {
            Some(&index) => {
                answer = answer + index;
            },
            None => {seen_chars.insert(c,i);}
        };
    }
    answer
}

(我还必须更改 answer 的类型才能编译它,因为 enumerate 给你 usizes 。或者,你可以转换 i必要时 u32)

如果出于某种原因,您希望使用字符串键而不是 char,则必须使用自有字符串(即 String)而不是字符串切片(&str ).你最终会得到这样的结果:

fn do_something(word:&str) -> usize {
    let mut seen_chars : HashMap<String,usize> = HashMap::new();
    let mut answer : usize = 0;
    for (i,c) in word.chars().enumerate() {
        let char_str = c.to_string();
        match seen_chars.get(&char_str) {
            Some(&index) => {
                answer = answer + index;
            },
            None => {seen_chars.insert(char_str,i);}
        };
    }
    answer
}

但我强烈怀疑第一个选项是您真正想要的。