У меня есть функция, называемая здесь request, которая возвращает строку JSON с некоторыми данными. Например, массив переменного размера. Я могу прекрасно десериализовать строку JSON в Vec с помощью serde_json, но мне приходится вызывать request много раз. Вместо этого я хотел бы повторно использовать уже созданный Vec, вместо того, чтобы удалять и создавать новый Vec каждый раз, когда происходит десериализация.
Есть ли способ десериализовать строку JSON в существующий Vec? Я посмотрел на посетителя и на этот пример, но не уверен, что мне придется реализовать. Либо пользовательский посетитель, либо десериализатор, который обертывает serde_json::Deserializer и имеет ссылку на Vec, либо, возможно, что-то совсем другое.
Вот код с примером. Спасибо.
use serde_json;
fn request(i: usize) -> String {
let mut v = vec![0; i];
for n in 1..i {
v[n] = n
}
serde_json::to_string(&v).unwrap()
}
fn main() {
let mut bigvec = serde_json::from_str::<Vec<i32>>(&request(100)).unwrap();
println!("{:?}", &bigvec);
// - now we will rerun the request many times and we would like to reuse our vec
let many_iterations = 10;
for n in 1..many_iterations {
bigvec.clear();
let resp = request(n); // we receive a new request with a vec with different length
// - we would like something like the below, which does not exist
serde_json::from_str_into::<Vec<i32>>(&resp, &mut bigvec);
}
}

Обновлено: я забыл о
serde::Deserialize::deserialize_in_place(скрытом в документации), когда писал этот ответ. Хотя этот ответ действительно показывает, как можно добиться аналогичных результатов с помощьюVisitor, я рекомендую вместо этого следовать ответуkmdreko.
Мы не можем полностью десериализовать все на месте, потому что serde спроектирован так, чтобы возвращать значение по мере его десериализации. Однако, если вы просто хотите десериализовать в один Vec, мы можем создать посетителя, который справится с этой ситуацией. Вот примерно как это будет выглядеть.
use serde::de::{DeserializeOwned, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt::{self, Formatter};
struct InPlaceVisitor<'a, T> {
buffer: &'a mut Vec<T>,
}
impl<'de, 'a: 'de, T> Visitor<'de> for InPlaceVisitor<'a, T>
where
T: Deserialize<'de>,
{
/// We are deserializing in place so we won't have any output
type Value = ();
/// Every visitor needs to implement this function to add some
/// context to error messages. This will be called if any of the
/// `visit_*` functions we didn't implement get called.
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "sequence of values")
}
/// Handle the case where the deserializer finds a sequence of
/// values.
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
// Clear the buffer before we begin
self.buffer.clear();
// If the deserializer knows the number of items in the
// sequence we can ensure we have enough capacity before
// starting. However, this is generally only the case for
// formats that prefix sequences with their lengths.
if let Some(hint) = seq.size_hint() {
self.buffer.reserve(hint);
}
// Now we can just read the values and add them to the
// buffer. This will call serde::Deserialize::deserialize for
// each element.
while let Some(value) = seq.next_element()? {
self.buffer.push(value);
}
Ok(())
}
}
Теперь одна из сложных частей использования этого заключается в том, что нам нужно создать нашего посетителя с буфером, в который мы хотим отправить. Это сложно, а это значит, что у нас не будет доступа к нашему буферу внутри serde::Deserialize::deserialize. В результате мы должны сами сконструировать десериализатор. Не все форматы serde раскрывают свои типы Serializer и Deserializer, поэтому это решение будет невозможно для всех форматов данных. К счастью, serde_json предоставляет свой десериализатор, поэтому мы можем реализовать общую функцию для использования нашего посетителя.
pub fn deserialize_json_in_place<'de, 'a: 'de, T, R>(
reader: R,
buffer: &'a mut Vec<T>,
) -> serde_json::Result<()>
where
T: Deserialize<'de>,
R: serde_json::de::Read<'de>,
{
let mut deserializer = serde_json::de::Deserializer::new(reader);
let visitor = InPlaceVisitor { buffer };
// We tell the deserializer what we are hoping to find, then the
// deserializer calls the `visit_*` function corresponding to the
// type it actually encountered.
deserializer.deserialize_seq(visitor)
}
С этим у нас все готово. Однако для удобства вы все равно можете захотеть создать несколько простых функций-оболочек для создания средства чтения.
pub fn from_str_into<T>(x: &str, buffer: &mut Vec<T>) -> serde_json::Result<()>
where
T: DeserializeOwned,
{
let reader = serde_json::de::StrRead::new(x);
deserialize_json_in_place(reader, buffer)
}
@fvall, ох вау. По иронии судьбы, я наполовину помнил, что что-то подобное существовало, поэтому проверил документацию serde и предположил, что путаю это с другим языком/библиотекой. Я даже не думал проверять скрытые функции. Надеюсь, этот ответ по-прежнему будет полезен для демонстрации того, как можно реализовать Visitor. Я оставлю этот ответ, но рекомендую вместо этого использовать решение kmdreko.
Существует скрытый1метод deserialize_in_place для типажа Deserialize, который может это поддержать. По умолчанию он просто создаст новое значение и присвоит его существующему, но имплант Vec делает именно то, что вы хотите.
Поэтому вам просто нужно вызвать его вручную с помощью десериализатора serde-json:
use serde::Deserialize;
use serde_json::Deserializer;
let mut deserializer = Deserializer::from_str(&resp);
Deserialize::deserialize_in_place(&mut deserializer, &mut bigvec).unwrap();
1. This is not a private API. The documentation says "This method is stable and an official public API, but hidden from the documentation because it is almost never what newbies are looking for."
Однако использование #[derive(Deserialize)] НЕ будет реализовано deserialize_in_place, если вы не включите функцию deserialize_in_place в serde_derive. Реализация Deserialize::deserialize_in_place по умолчанию просто вызывает Deserialize::deserialize. Это означает, что вызов deserialize_in_place не всегда будет выполнять десериализацию на месте.
#[derive(Deserialize)]
struct Foo {
a: Vec<i32>,
}
let mut foo = Foo { a: Vec::new() };
for data in example_data {
// If the `deserialize_in_place` feature is not enabled, this call will result
// in a new `Vec` being created every call.
let mut deserializer = Deserializer::from_str(&resp);
Foo::deserialize_in_place(&mut deserializer, &mut foo).unwrap();
}
ИМХО, скрывать это - ошибка. Я никогда об этом не знал...
@ChayimFriedman см. github.com/serde-rs/serde/issues/2204
Спасибо за совет. Возможно, мне придется просмотреть исходный код вместо того, чтобы обращаться к docs.rs, чтобы найти эти вещи. В приведенном выше примере я работал нормально, но как только я поместил vec в структуру и попытался сериализовать структуру на месте, это больше не работало. Поэтому я думаю, что мне придется реализовать свою собственную версию десериализации. Принимаю ответ, поскольку более сложный случай не был частью моего вопроса.
Спасибо за объяснение. Учитывая другой ответ выше с
deserialize_in_place, возможно, можно реализоватьdeserialize_in_placeдля структуры, используя ваше предложение кода. В моем реальном случае использования, я думаю, мне нужно будет каким-то образом объединить оба ответа в этом посте, поскольку стандартный вариантdeserialize_in_placeне работает для более сложной структуры с векторами в ней.