Недавно я начал изучать Rust и в настоящее время пытаюсь создать набор данных из поддельного API, чтобы манипулировать данными после их извлечения и десериализации:
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct Post {
user_id: i32,
id: i32,
title: String,
body: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Begin: important part
let posts = reqwest::get("https://jsonplaceholder.typicode.com/posts")
.await?
.json::<Vec<Post>>()
.await?;
let posts = posts
.iter()
.map(|post| post) // Imagine manipulating the post here, somehow
.collect::<Vec<&Post>>();
// End: important part
println!("{:#?}", posts);
Ok(())
}
Это прекрасно работает. Однако я не понимаю, почему приведенное выше работает, а не работает при попытке выполнить всю операцию за один раз, например:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Begin: important part
let posts = reqwest::get("https://jsonplaceholder.typicode.com/posts")
.await?
.json::<Vec<Post>>()
.await?
.iter()
.map(|post| post) // Imagine manipulating the post here, somehow
.collect::<Vec<&Post>>();
// End: important part
println!("{:#?}", posts);
Ok(())
}
без ошибки:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:15:17
|
15 | let posts = reqwest::get("https://jsonplaceholder.typicode.com/posts")
| _________________^
16 | | .await?
17 | | .json::<Vec<Post>>()
18 | | .await?
| |_______________^ creates a temporary value which is freed while still in use
...
21 | .collect::<Vec<&Post>>();
| - temporary value is freed at the end of this statement
...
24 | println!("{:#?}", posts);
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Я ожидал, что эти два подхода к проблеме дадут один и тот же результат, и я не понимаю, почему один работает, а другой выдает ошибку, и, честно говоря, я тоже не понимаю сообщения об ошибке.
Что именно я делаю неправильно, здесь? Я подозреваю, что у него может быть что-то связанное с чертами, но я не понимаю, почему тогда он не потерпит неудачу (или не преуспеет, соответственно) в обоих случаях.

Error: value of type `Vec<&Post>` cannot be built from `std::iter::Iterator<Item=&Vec<Post>>
указывает на различия в возвращаемых типах обоих подходов.
Во втором подходе вы пытаетесь собрать Vec<&Post> непосредственно из Iterator<Item=&Post>, возвращенного .iter() в десериализованном Vec<Post>. Это не работает, потому что метод .iter() возвращает итератор по ссылкам на объекты Post, а не ссылки на ссылки на объекты Post (именно это Vec<&Post> expects).
Вопрос, который вы должны задать себе: во втором примере вы хотите собрать векторы заимствованных Posts; кому принадлежат Posts? В первом примере вектор принадлежит переменной posts, поэтому вы можете перебирать ссылки на элементы внутри вектора; но во втором случае вектор строится методом .json(), перемещается «к вам», но вы его не храните где-то, а сразу потребляете для извлечения ссылок на то, что в нем содержится; как только оператор завершится, построенный промежуточный вектор будет удален (т. е. освобожден), а ссылки станут недействительными.
Возможно, вы не получили приятное сообщение об ошибке из-за манипуляций в вызове .map(...), однако сообщение об ошибке, которое я получаю с вашим примером,
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:18:17
|
18 | let posts = reqwest::get("https://jsonplaceholder.typicode.com/posts")
| _________________^
19 | | .await?
20 | | .json::<Vec<Post>>()
21 | | .await?
| |_______________^ creates a temporary value which is freed while still in use
...
24 | .collect::<Vec<&Post>>();
| - temporary value is freed at the end of this statement
...
28 | println!("{:#?}", posts);
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Вы видите, что Rust предлагает вам сделать именно то, что вы сделали.
@SvenMarnach Спасибо, это помогло мне почти так же, как и правильный ответ, потому что он заставил меня щелкнуть что-то, что уже должно было щелкнуть.
Я полностью неправильно понял полезную ошибку компилятора, но ваш ответ открыл мне глаза, спасибо!
Однако в этом конкретном случае вы не должны следовать подсказке компилятора, а скорее замените
iter()наinto_iter()и соберете вVec<Post>. В противном случае будет невозможно сделать какие-либо модификации на постах. Все, что вы могли бы сделать, это собрать ссылки на точные сообщения в первом векторе во второй вектор, что кажется довольно бессмысленным.