有人会友好地向我解释为什么在此脚本中使用String
不起作用,&str
会这样做。另外,我如何修改它以便它可以与String
一起使用? [版本1.2]
use std::collections::{HashMap};
fn main() {
let mut hash = HashMap::<&str, &str>::new();
hash.insert("this", "value");
let l: &str = "this is a borrowed string reference";
// If the above line was defined as:
//let l: String = "this is a string".to_string();
let mut all = l.split(" ");
let name: &str = all.next().unwrap();
if hash.contains_key(name) == true {
hash.remove(name);
} else {
hash.insert(name, "stuff");
}
}
答案 0 :(得分:5)
好的,让我们把它归结为必需品:
use std::collections::HashMap;
fn main() {
let mut hash = HashMap::<&str, &str>::new();
hash.insert("this", "value");
let l: String = "this is a borrowed string reference".to_string();
hash.insert(&l, "stuff");
}
编译这个给我们:
<anon>:7:18: 7:19 error: `l` does not live long enough
<anon>:7 hash.insert(&l, "stuff");
^
<anon>:4:49: 8:2 note: reference must be valid for the block suffix following statement 0 at 4:48...
<anon>:4 let mut hash = HashMap::<&str, &str>::new();
<anon>:5 hash.insert("this", "value");
<anon>:6 let l: String = "this is a borrowed string reference".to_string();
<anon>:7 hash.insert(&l, "stuff");
<anon>:8 }
<anon>:6:71: 8:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 6:70
<anon>:6 let l: String = "this is a borrowed string reference".to_string();
<anon>:7 hash.insert(&l, "stuff");
<anon>:8 }
它或多或少地告诉你完全它不起作用。您尝试将借用的指针插入到String
l
到hashmap中。但是,String
的效果还不够长。
具体而言,Rust以反向词汇顺序销毁值。因此,当执行到达函数末尾时,Rust将首先释放l
,然后释放hash
。这是一个问题:它意味着有一个窗口,其中hash
包含指向已销毁数据的指针,Rust绝对将不允许。
这适用于&str
的原因是字符串文字"like this"
不仅仅是&str
;它实际上是&'static str
。这意味着字符串文字在程序的整个持续时间内“存在”:它从不被破坏,因此hashmap可以安全地保存指向它的指针。
解决方案是确保String
比HashMap
:
use std::collections::HashMap;
fn main() {
// Declare `l` here ...
let l;
let mut hash = HashMap::<&str, &str>::new();
hash.insert("this", "value");
// ... but initialise it *here*.
l = "this is a borrowed string reference".to_string();
hash.insert(&l, "stuff");
}
现在,hash
首先被摧毁,然后是l
。只要你在阅读或使用它之前做初始化它就可以保留未初始化的变量。
答案 1 :(得分:2)
如果您将l
更改为String
,则会获得:
错误:
l
活得不够长
这是真的:
name
是对l
的一个子字符串的引用。您可能会将name
引用插入hash
,但hash
的生命周期比l
的生命周期长。因此,当l
的生命周期结束时,hash
将包含无效引用。这是不允许的。 F.ex.如果删除insert
行,Rust很高兴。
根据您的需要,有多种方法可以解决这个问题。其中之一是hash
的生命周期短于l
的生命周期,通过在hash
之后实例化l
:
use std::collections::{HashMap};
fn main() {
// let l: &str = "this is a borrowed string reference";
// If the above line was defined as:
let l: String = "this is a string".to_string();
let mut hash = HashMap::<&str, &str>::new();
hash.insert("this", "value");
let mut all = l.split(" ");
let name: &str = all.next().unwrap();
if hash.contains_key(name) == true {
hash.remove(name);
} else {
hash.insert(name, "stuff");
}
}
或者,您可以在地图中存储字符串的副本。
答案 2 :(得分:1)
您有终身问题。
插入hash
的任何对象只能引用比hash
更长的内容(或根本不引用任何内容)。
但是,在此处,您在l
之后定义hash
,因此l
的生命周期更短。反过来,这意味着引用name
缓冲区的l
的生命周期比hash
更短,因此name
不适合插入hash
(虽然它可以用来搜索/删除)。
切换定义l
和hash
的顺序使其有效:
use std::collections::{HashMap};
fn main() {
let l: String = "this is a string".to_string();
let mut hash = HashMap::<&str, &str>::new();
hash.insert("this", "value");
let mut all = l.split(" ");
let name: &str = all.next().unwrap();
if hash.contains_key(name) == true {
hash.remove(name);
} else {
hash.insert(name, "stuff");
}
}
如果无法做到这一点,请使用HashMap<String, String>
来避免生命周期问题。