在循环中引用集合项时,装箱或显式生命周期是正确的解决方案吗?
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
给你 usize
s 。或者,你可以转换 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
}
但我强烈怀疑第一个选项是您真正想要的。
在 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
给你 usize
s 。或者,你可以转换 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
}
但我强烈怀疑第一个选项是您真正想要的。