【问题标题】:to_string() causes error "borrowed value does not live long enough"to_string() 导致错误“借来的值不够长”
【发布时间】:2016-09-20 02:44:04
【问题描述】:

为什么to_string() 会导致borrowed value does not live long enough 错误?下面的例子:

use std::collections::HashMap;

struct Foo {
    id: Option<usize>,
    name: String
}

fn main() {

    let foos = getFoos();

    for foo in foos {
        let mut map = HashMap::new();
        map.insert("name", &foo.name);
        map.insert("id", &foo.id.unwrap().to_string());
    }

}

fn getFoos() -> Vec<Foo> {
    Vec::new()
}

错误:

src/main.rs:15:27: 15:54 error: borrowed value does not live long enough
src/main.rs:15         map.insert("id", &foo.id.unwrap().to_string());
                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:13:38: 16:6 note: reference must be valid for the block suffix following statement 0 at 13:37...
src/main.rs:13         let mut map = HashMap::new();
src/main.rs:14         map.insert("name", &foo.name);
src/main.rs:15         map.insert("id", &foo.id.unwrap().to_string());
src/main.rs:16     }
src/main.rs:15:9: 15:56 note: ...but borrowed value is only valid for the statement at 15:8
src/main.rs:15         map.insert("id", &foo.id.unwrap().to_string());
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:15:9: 15:56 help: consider using a `let` binding to increase its lifetime
src/main.rs:15         map.insert("id", &foo.id.unwrap().to_string());
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

为什么编译器建议创建中间值?这个错误令人困惑。

【问题讨论】:

  • 您正在引用to_string 生成的值。只需删除&amp;,您的代码就可以工作:play.rust-lang.org/…
  • @ker 我不认为这是重复的。类似,是的,但仍然有足够的不同 IMO :)
  • 您可能不想在地图中插入对字符串的引用。只需删除所有 & 运算符。

标签: rust lifetime borrow-checker


【解决方案1】:

您正在创建一个HashMap 来保存对字符串的引用,即&amp;String。如果我们要注解类型,它看起来像这样:

let mut map: HashMap<&str, &String> = HashMap::new();

这意味着地图包含大量对生活在其他地方的对象的引用。在您的第一个插入中,它工作得非常好,因为 foo.name 存在于其他地方,特别是在对象 foo 中。

map.insert("name", &foo.name);

但是你的第二个插入有一个问题:你想引用一个 String 对象,它存在于某个地方。 to_string() 创建一个由函数返回的 String,但在您的情况下,它只是一个临时对象。该对象将在该行执行后被销毁。

map.insert("id", &foo.id.unwrap().to_string());

编译器是对的:let 绑定可以解决这里的问题。

let mut map = HashMap::new();
map.insert("name", &foo.name);
let id_string = foo.id.unwrap().to_string();
map.insert("id", &id_string);

这在您的小示例中效果很好,但是当您处理更大的事情时可能会更复杂。例如,如果 HashMap 将在循环之外定义,您将遇到问题,因为您插入到地图中的引用至少需要与地图本身一样长。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 2014-12-26
    • 2019-11-29
    • 2017-03-11
    相关资源
    最近更新 更多