Как вернуть значение состояния из конечной точки Rocket? - PullRequest
0 голосов
/ 17 июня 2019

Я храню данные из внешней службы в локальном кэше и хочу создать конечную точку для возврата данных, находящихся в данный момент в кэше.

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;

use rocket::{Route, State};
use rocket_contrib::json::Json;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct Post {
    pub title: String,
    pub body: String,
}

impl Post {
    pub fn new(title: String, body: String) -> Post {
        Post { title, body }
    }
}

pub struct Cache {
    pub posts: Vec<Post>,
}

impl Cache {
    pub fn new() -> Cache {
        let mut posts = vec![
            Post::new(String::from("Article1"), String::from("Blah")),
            Post::new(String::from("Article2"), String::from("Blah")),
            Post::new(String::from("Article3"), String::from("Blah")),
            Post::new(String::from("Article4"), String::from("Blah")),
            Post::new(String::from("Article5"), String::from("Blah")),
        ];

        Cache { posts }
    }
}

#[derive(Responder)]
pub enum IndexResponder {
    #[response(status = 200)]
    Found(Json<Vec<Post>>),
    #[response(status = 404)]
    NotFound(String),
}

#[get("/")]
pub fn index(cache: State<Cache>) -> IndexResponder {
    return IndexResponder::Found(Json(cache.posts));
}

fn main() {
    rocket::ignite()
        .mount("/", routes![index])
        .manage(Cache::new())
        .launch();
}

Компилятор жалуется:

error[E0507]: cannot move out of dereference of `rocket::State<'_, Cache>`
  --> src/main.rs:50:39
   |
50 |     return IndexResponder::Found(Json(cache.posts));
   |                                       ^^^^^^^^^^^ move occurs because value has type `std::vec::Vec<Post>`, which does not implement the `Copy` trait

(cargo build --verbose вывод )

Файл My Cargo.toml:

[package]
name = "debug-project"
version = "0.1.0"
authors = ["Varkal <mail@example.com>"]
edition = "2018"

[dependencies]
rocket = "0.4.0"
rocket_contrib = "0.4.0"
serde = { version = "1.0.90", features = ["derive"] }
serde_json = "1.0.39"

Очень простой репозиторий для воспроизведения ошибки .

1 Ответ

0 голосов
/ 19 июня 2019

Ваша конечная точка не владеет государством и, следовательно, не может вернуть принадлежащее Vec<Post>. Концептуально это имеет смысл, потому что если бы вы взяли право собственности на него, то какое значение будет присутствовать при следующем вызове конечной точки?

Самое простое, что вы можете сделать, это клонировать данные:

#[get("/")]
pub fn index(cache: State<Cache>) -> IndexResponder {
    IndexResponder::Found(Json(cache.posts.clone()))
}

Для этого вам потребуется реализовать Clone для Post или, возможно, изменить свое состояние, чтобы оно содержало что-то вроде Arc.

Немного более производительным решением является возврат среза, который относится к состоянию. Это не требует клонирования, но требует использования метода State::inner:

#[derive(Responder)]
pub enum IndexResponder<'a> {
    #[response(status = 200)]
    Found(Json<&'a [Post]>),
    #[response(status = 404)]
    NotFound(String),
}

#[get("/")]
pub fn index<'a>(cache: State<'a, Cache>) -> IndexResponder<'a> {
    IndexResponder::Found(Json(&cache.inner().posts))
}

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...