char 到 string 转换的所有权问题
Ownership problem with char to string conversion
我的失败代码(Minimal, Reproducible Example):
// my code
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [char; 3] = ['a', 'b', 'c'];
for (i, _) in ARRAY.iter().enumerate() {
list.push(Text::new(&ARRAY[i].to_string()));
}
}
// external crate
#[derive(Debug, Clone, Copy, PartialEq)]
struct Text<'a> {
pub text: &'a str,
}
impl<'a> Text<'a> {
pub fn new(text: &'a str) -> Self {
Text {
text
}
}
}
编译器:“借用时删除了临时值”。下面的红色波浪线
ARRAY[i].to_string()
我猜是经典借用检查器问题?
我尝试将类型更改为 &str
s 而不是 char
s 并且一切正常:
// my code
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [&str; 3] = ["a", "b", "c"]; // CHANGE HERE
for (i, _) in ARRAY.iter().enumerate() {
list.push(Text::new(&ARRAY[i])); // CHANGE HERE
}
}
无法弄清楚 char
或使用 to_string()
的转换有何特别之处导致此代码失败。
特别之处在于 to_string()
创建一个拥有的字符串,而 "..."
给你一个 &'static str
。拥有的字符串有一个明确的生命周期,当它释放存储数据的内存时,它会在其作用域结束时结束。您尝试将 references 存储到此类字符串,并在字符串已被释放后保留它们。
外部板条箱中的 Text
类型旨在 借用 其他人拥有的数据。如果你不能改变它,你只需要确保你拥有的值至少与 Text
值一样长。例如:
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [char; 3] = ['a', 'b', 'c'];
// keep the strings live
let strings: Vec<String> = ARRAY.iter().map(|c| c.to_string()).collect();
// `Text`s in `list` refer to strings in `strings`
for s in &strings {
list.push(Text::new(s));
}
}
您的失败代码等同于此代码:
for a in &ARRAY {
let temp = a.to_string();
list.push(Text::new(&temp));
drop(temp);
}
除了临时变量在我的代码中有一个名称(对 drop()
的调用是多余的,为了清楚起见我添加了它)。
所以在循环期间创建的所有临时对象都作为引用添加到列表中,请记住 Text
持有一个引用,而不是字符串本身。但是这些临时对象不会在创建它们的迭代中存活下来,因此您的列表包含悬空引用。 Rust 检测到并无法编译。
简单的解决方案是修改 Text
以保存 String
本身,而不是引用。如果你不能修改它,那么你的字符串必须存在于某个地方,你可以构建一个 Vec<String>
并从那里获取引用:
fn test() {
const ARRAY: [char; 3] = ['a', 'b', 'c'];
let mut tmps: Vec<String> = Vec::new();
for a in &ARRAY {
tmps.push(a.to_string());
}
let list: Vec<Text> = tmps
.iter()
.map(|s| Text::new(s))
.collect();
}
您的第二个代码之所以有效,是因为现在您的数组包含静态引用 &'static str
,因此任何地方都没有临时变量。
我的失败代码(Minimal, Reproducible Example):
// my code
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [char; 3] = ['a', 'b', 'c'];
for (i, _) in ARRAY.iter().enumerate() {
list.push(Text::new(&ARRAY[i].to_string()));
}
}
// external crate
#[derive(Debug, Clone, Copy, PartialEq)]
struct Text<'a> {
pub text: &'a str,
}
impl<'a> Text<'a> {
pub fn new(text: &'a str) -> Self {
Text {
text
}
}
}
编译器:“借用时删除了临时值”。下面的红色波浪线
ARRAY[i].to_string()
我猜是经典借用检查器问题?
我尝试将类型更改为 &str
s 而不是 char
s 并且一切正常:
// my code
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [&str; 3] = ["a", "b", "c"]; // CHANGE HERE
for (i, _) in ARRAY.iter().enumerate() {
list.push(Text::new(&ARRAY[i])); // CHANGE HERE
}
}
无法弄清楚 char
或使用 to_string()
的转换有何特别之处导致此代码失败。
特别之处在于 to_string()
创建一个拥有的字符串,而 "..."
给你一个 &'static str
。拥有的字符串有一个明确的生命周期,当它释放存储数据的内存时,它会在其作用域结束时结束。您尝试将 references 存储到此类字符串,并在字符串已被释放后保留它们。
外部板条箱中的 Text
类型旨在 借用 其他人拥有的数据。如果你不能改变它,你只需要确保你拥有的值至少与 Text
值一样长。例如:
fn test() {
let mut list: Vec<Text> = Vec::new();
const ARRAY: [char; 3] = ['a', 'b', 'c'];
// keep the strings live
let strings: Vec<String> = ARRAY.iter().map(|c| c.to_string()).collect();
// `Text`s in `list` refer to strings in `strings`
for s in &strings {
list.push(Text::new(s));
}
}
您的失败代码等同于此代码:
for a in &ARRAY {
let temp = a.to_string();
list.push(Text::new(&temp));
drop(temp);
}
除了临时变量在我的代码中有一个名称(对 drop()
的调用是多余的,为了清楚起见我添加了它)。
所以在循环期间创建的所有临时对象都作为引用添加到列表中,请记住 Text
持有一个引用,而不是字符串本身。但是这些临时对象不会在创建它们的迭代中存活下来,因此您的列表包含悬空引用。 Rust 检测到并无法编译。
简单的解决方案是修改 Text
以保存 String
本身,而不是引用。如果你不能修改它,那么你的字符串必须存在于某个地方,你可以构建一个 Vec<String>
并从那里获取引用:
fn test() {
const ARRAY: [char; 3] = ['a', 'b', 'c'];
let mut tmps: Vec<String> = Vec::new();
for a in &ARRAY {
tmps.push(a.to_string());
}
let list: Vec<Text> = tmps
.iter()
.map(|s| Text::new(s))
.collect();
}
您的第二个代码之所以有效,是因为现在您的数组包含静态引用 &'static str
,因此任何地方都没有临时变量。