2016-05-23 4 views
2

Почему to_string() вызывает borrowed value does not live long enough Ошибка? Пример ниже:to_string() вызывает ошибку "заемное значение не проживает достаточно долго"

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()); 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

Почему компилятор предполагает создать промежуточное значение? Эта ошибка запутанна.

+0

Вы принимаете ссылку на значение, генерируемое 'to_string'. Просто удалите '&' и ваш код будет работать: https://play.rust-lang.org/?gist=b41ea549d5b4add70559827b7d41e58a&version=stable&backtrace=0 –

+0

Возможный дубликат [Возврат локальной строки в виде среза (& str)] (http: //stackoverflow.com/questions/29428227/return-local-string-as-a-slice-str) –

+1

@ker Я не думаю, что это дубликат. Аналогично да, но все равно достаточно IMO :) –

ответ

4

Вы создаете файл HashMap, который сохраняет ссылки на строки, а именно &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 будет определен за пределами цикла, у вас возникнет проблема, потому что ссылка, которую вы вставляете в карту, должна жить как минимум до тех пор, пока сама карта.

 Смежные вопросы

  • Нет связанных вопросов^_^