Время жизни при десериализации JSON внутри FromForm
У меня проблемы с пониманием отношений между временами жизни в этом коде. По сути, у меня есть Rocket API, который получает некоторые x-www-form-urlencoded
данные только с одним ключом: json
, Этот ключ интуитивно содержит значение JSON, закодированное с помощью процентного кодирования, структуры Message<T>
,
(Я знаю, что это неоптимальный дизайн API, но это реверс-инжиниринг, поэтому у меня нет выбора)
Быть легко используемым в качестве охранника From<Message<T>>
Я реализую FromForm
, Для этого мне нужно реализовать FromForm<'f>
для любого Message<T>
где T
инвентарь Deserialize<'de>
, Я написал свою подпись как impl<'f, 'de, T> FromForm<'f> for Message<T> where T: Deserialize<'de>
,
Чтобы фактически выполнить декодирование, я:
- Получить
"json"
ключ данных формы; - URL-декодировать значение;
- Разбор JSON содержится в значении.
Выручать как можно скорее. Код, делающий это (явные аннотации типов для удобства читателя):
fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Self, Self::Error> {
// Get JSON field
let encoded: Option<&RawStr> = items.find(|&(k, _)| k.as_str() == "json")
.map(|(_, v)| v);
if let None = encoded {
return Err(MessageFormError::MissingJsonKey);
}
// Decode URL-string
let decoded: Result<String, Utf8Error> = encoded.unwrap().url_decode();
if let Err(e) = decoded {
return Err(MessageFormError::InvalidUrl(e));
}
// Parse JSON
let json: String = decoded.unwrap();
serde_json::from_str::<Self>(&json) // Line 205
.map_err(|e| MessageFormError::InvalidJson(e))
}
Gist, демонстрирующий проблему методом вставки и запуска (не работает на игровой площадке, поскольку зависит от Rocket).
Насколько я понимаю:
&RawStr
изencoded
имеет жизнь'f
,String
создан из этогоurl_decode
, который живет до конца функцииserde_json
занимает&'x str
где'x
не должен совпадать с'de
, и возвращает значение (таким образом, оно доживает до конца функции и, поскольку оно возвращается, выходит за его пределы)
Но, похоже, мое понимание неверно:
205 | serde_json::from_str::<Self>(&json)
| ^^^^ does not live long enough
206 | .map_err(|e| MessageFormError::InvalidJson(e))
207 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'f as defined on the impl at 184:1...
--> src/transport.rs:184:1
|
184 | / impl<'f, T> FromForm<'f> for Message<T>
185 | | where T: Deserialize<'f>
186 | | {
187 | | type Error = MessageFormError;
... |
207 | | }
208 | | }
| |_^
Что я делаю не так и как правильно вернуть десериализованное значение?
1 ответ
Этот раздел сайта Serde охватывает Deserialize
границы в деталях.
Есть два основных способа написания
Deserialize
границы черты, будь то в блоке impl или функции или где-либо еще.
<'de, T> where T: Deserialize<'de>
Это означает, что "T может быть десериализован с некоторой жизни". Звонящий решает, что это за жизнь. Обычно это используется, когда вызывающая сторона также предоставляет данные, из которых выполняется десериализация, например, в такой функции, как
serde_json::from_str
, В этом случае входные данные также должны иметь время жизни'de
Например, это может быть&'de str
,
<T> where T: DeserializeOwned
Это означает, что "T может быть десериализован из любой жизни". Вызываемый должен решить, какая жизнь. Обычно это происходит потому, что данные, из которых выполняется десериализация, будут выброшены до возврата из функции, поэтому нельзя допускать, чтобы T заимствовал из нее. В вашем случае данные поступают от URL-декодирования некоторого ввода, а декодированные данные выбрасываются после десериализации T. Другое распространенное использование этой границы - функции, которые десериализуются из потока ввода-вывода, такие как
serde_json::from_reader
,Чтобы сказать это более технически,
DeserializeOwned
признак эквивалентен признаку признака более высокого рангаfor<'de> Deserialize<'de>
, Единственная разницаDeserializeOwned
более интуитивно понятен для чтения. Это означает, что T владеет всеми данными, которые десериализуются.
Замена вашего T: Deserialize<'f>
связано с T: DeserializeOwned
правильно сообщает, что T нельзя заимствовать из данных, декодированных по URL, потому что данные, декодированные по URL, не переживут T.