Каков Rust-способ вызова метода, требующего фрагмента строки из строки

#rust #serde

#Ржавчина #serde

Вопрос:

Я новичок в rust (но опытный программист), и я пытаюсь создать простую служебную функцию для чтения данных из файла json, и мне явно не хватает важного понимания rust, чтобы справиться с этим. Я огляделся, но не смог заставить его работать с другими вопросами rust. Я пытаюсь сделать что-то вроде этого:

 pub fn read_data_from_json<'a, T: Deserialize<'a>, P: AsRef<Path>>(path: P) -> T {
    let result = std::fs::read_to_string(path).unwrap();
    return serde_json::from_str(amp;result).unwrap();
}
 

Проблема в том, что я хочу предоставить serde_json::from_str() amp;str требуемое, но получаю a String от чтения файла. Итак, компилятор rust говорит:

 40 |     return serde_json::from_str(amp;result).unwrap();
   |            ---------------------^^^^^^^-
   |            |                    |
   |            |                    borrowed value does not live long enough

 

Причина, очевидно, в том, что result переменная удаляется до from_str() завершения работы со значением, но я не смог получить «только фрагмент» со значением. Я пробовал as_str() , amp;* , amp;'static str и несколько других вариантов, чтобы попытаться заставить это работать, но я явно что-то упускаю, поскольку это похоже на базовый вариант использования. Я должен признать, что я все еще немного нечетко понимаю «время жизни» и связанные с ним дженерики, поэтому проблема может быть там.

Комментарии:

1. Эта страница документации представляет довольно точно вашу ситуацию: docs.serde.rs/serde/de/trait . DeserializeOwned.html

Ответ №1:

Я бы посоветовал вам прочитать «Понимание времени жизни десериализатора» из руководства serde. Там они предлагают T: DeserializeOwned , явно упоминая ваш usecase:

Обычно это происходит потому, что данные, из которых десериализуются, будут удалены до возврата функции, поэтому T им нельзя разрешать заимствовать из нее.

Итак, решение таково:

 use serde::de::DeserializeOwned;

pub fn read_data_from_json<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> T {
    let result = std::fs::read_to_string(path).unwrap();
    return serde_json::from_str(amp;result).unwrap();
}
 

Комментарии:

1. Обратите внимание, что это может повлечь за собой изменение структуры для десериализации, поскольку она должна владеть своими данными.

2. Хорошо, интересно, но является ли это проблемой только для serde- способа сериализации с нулевой копией? Я подумал, что это общая вещь с заимствованием, которую мне нужно понять. Я чувствую, что должен иметь возможность указать Rust, чтобы он просто сохранял ссылку до завершения функции / области видимости, или что мне просто нужен фрагмент, а не объект string.

3. @leondepeon Rust сохранял ссылку до тех пор, пока функция / область не завершилась. Ваш from_str() вызов был бы хорош, если бы вы присвоили его результат локальной переменной и использовали его внутри функции, чтобы он не пережил result . Но вы попытались вернуть сконструированное значение, а это недопустимо, потому что ссылки с нулевой копией внутри него останутся висячими после result удаления.