rust - 函数局部变量的生命周期不够长

标签 rust serde serde-json

<分区>

我正在尝试围绕 serde_json 和 Rocket 的 FromData 编写一个包装器,以强类型化我与服务器交换的一些 JSON。

我无法编译以下代码:

extern crate serde_json;
extern crate rocket;
extern crate serde;

use serde::ser::Error;
use serde_json::Value;

use rocket::data::DataStream;
use rocket::outcome::IntoOutcome;

use std::io::Read;

static NULL: Value = serde_json::Value::Null;

pub struct ResponseJSON<'v> {
    success: bool,
    http_code: u16,
    data: &'v serde_json::Value,
}

impl<'v> ResponseJSON<'v> {
    pub fn ok() -> ResponseJSON<'v> {
        ResponseJSON {
            success: true,
            http_code: 200,
            data: &NULL,
        } 
    }
    pub fn http_code(mut self, code: u16) -> ResponseJSON<'v> {
        self.http_code = code;
        self
    }
    pub fn data(mut self, ref_data: &'v serde_json::Value) -> ResponseJSON<'v> {
        self.data = ref_data;
        self
    }

    pub fn from_serde_value(json: &'v serde_json::Value) -> ResponseJSON<'v> {
        if !json["success"].is_null() {
            ResponseJSON::ok()
                .http_code(json["http_code"].as_u64().unwrap() as u16)
                .data(json.get("data").unwrap_or(&NULL))
        } else {
            ResponseJSON::ok()
                .data(json.pointer("").unwrap())
        }
    }
}

impl<'v> rocket::data::FromData for ResponseJSON<'v> {
    type Error = serde_json::Error;

    fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
        if !request.content_type().map_or(false, |ct| ct.is_json()) {
            println!("Content-Type is not JSON.");
            return rocket::Outcome::Forward(data);
        }

        let data_from_reader = data.open().take(1<<20);
        let value = serde_json::from_reader(data_from_reader);
        let unwraped_value : Value = if value.is_ok() { value.unwrap() } else { Value::Null };

        if !unwraped_value.is_null() {
            Ok(ResponseJSON::from_serde_value(&unwraped_value)).into_outcome()
        } else {
            Err(serde_json::Error::custom("Unable to create JSON from reader")).into_outcome()
        }
    }
}

fn main() {
    println!("it runs!");
}

编译器的错误:

   Compiling tests v0.1.0 (file:///Users/bgbahoue/Projects.nosync/tests)
error: `unwraped_value` does not live long enough
  --> src/main.rs:64:48
   |
64 |             Ok(ResponseJSON::from_serde_value(&unwraped_value)).into_outcome()
   |                                                ^^^^^^^^^^^^^^ does not live long enough
...
68 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'v as defined on the body at 53:114...
  --> src/main.rs:53:115
   |
53 |       fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
   |  ___________________________________________________________________________________________________________________^
54 | |         if !request.content_type().map_or(false, |ct| ct.is_json()) {
55 | |             println!("Content-Type is not JSON.");
56 | |             return rocket::Outcome::Forward(data);
...  |
67 | |         }
68 | |     }
   | |_____^

error: aborting due to previous error

由于 data_from_readervalueunwraped_value 来自 data 我认为编译器可以推断它具有同样的一生,但显然并非如此。在这种情况下,我有什么方法可以说明或做一些有用的事情吗?

serde_json::from_reader :

pub fn from_reader<R, T>(rdr: R) -> Result<T> 
where
    R: Read,
    T: DeserializeOwned, 

rocket::data::Data::open :

fn open(self) -> DataStream

rocket::data::DataStream::take :

fn take(self, limit: u64) -> Take<Self>

最佳答案

根据上面@LukasKalbertodt 的评论,当 ResponseJSON 拥有 serde_json::Value

时它确实有效

修改后的代码(按原样粘贴,即使有更好的方法链接代码的某些部分)

#![allow(dead_code)]

extern crate serde_json;
extern crate rocket;
extern crate serde;

use serde::ser::Error;
use serde_json::Value;

use rocket::outcome::IntoOutcome;

use std::io::Read;

static NULL: Value = serde_json::Value::Null;

pub struct ResponseJSON { // <-- changed to remove the lifetime parameter
    success: bool,
    http_code: u16,
    data: serde_json::Value, // <- changed to remove the '&'
}

impl ResponseJSON {
    pub fn ok() -> ResponseJSON {
        ResponseJSON {
            success: true,
            http_code: 200,
            data: Value::Null,
        } 
    }
    pub fn http_code(mut self, code: u16) -> ResponseJSON {
        self.http_code = code;
        self
    }
    pub fn data(mut self, data: serde_json::Value) -> ResponseJSON { // <- changed to remove the '&'
        self.data = data;
        self
    }

    pub fn from_serde_value(json: serde_json::Value) -> ResponseJSON { // <- changed to remove the reference & lifetime parameter
        if !json["success"].is_null() {
            ResponseJSON::ok()
                .http_code(json["http_code"].as_u64().unwrap() as u16)
                .data(json.get("data").unwrap_or(&NULL).clone())
        } else {
            ResponseJSON::ok()
                .data(json.pointer("").unwrap().clone())
        }
    }
}

impl rocket::data::FromData for ResponseJSON {
    type Error = serde_json::Error;

    fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
        if !request.content_type().map_or(false, |ct| ct.is_json()) {
            println!("Content-Type is not JSON.");
            return rocket::Outcome::Forward(data);
        }

        let data_from_reader = data.open().take(1<<20);
        let value = serde_json::from_reader(data_from_reader);
        let unwraped_value : Value = if value.is_ok() { value.unwrap() } else { Value::Null };

        if !unwraped_value.is_null() {
            Ok(ResponseJSON::from_serde_value(unwraped_value)).into_outcome() // <- changed to remove the '&' in front of `unwraped_value`
        } else {
            Err(serde_json::Error::custom("Unable to create JSON from reader")).into_outcome()
        }
    }
}

fn main() {
    println!("it compiles & runs");
}

cargo run 输出

   Compiling tests v0.1.0 (file:///Users/bgbahoue/Projects.nosync/tests)
    Finished dev [unoptimized + debuginfo] target(s) in 1.28 secs
     Running `target/debug/tests`
it compiles & runs

我的看法是,在那种情况下,输入参数的 data 的所有权(生命周期?)被传递给 data_from_readervalueunwraped_value 到返回的 rocket::data::Outcome 的临时 ResponseJSON;所以看起来还可以。

有了引用,临时 ResponseJSON 并没有比函数结束时长,因为它比创建它的 serde_json::Value 长,即 unwraped_value 生命周期,即函数的生命周期结尾;因此是编译器问题。

虽然不是 100% 肯定我的解释,但希望你对此有想法

关于rust - 函数局部变量的生命周期不够长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44014399/

相关文章:

rust - 错误警告 "value assigned is never read"

rust - 是否可以使用类型来访问 Rust 联合的特定字段?

rust - 如何避免 Serde 需要跳过序列化的字段的默认特征?

json - 使用 serde_json 反序列化 JSON 根数组

rust - 在 Rust 中使用 return 语句和省略分号有什么区别?

serialization - 如何在不包含枚举变体名称的情况下序列化枚举?

rust - 为什么不允许在格式中重复使用相同的值!宏观

rust - 对特定功能而不是整个实现的特征约束

rust - 使用serde_cbor在Rust中将Vec <u8>序列化为CBOR字节字符串

rust - 如何将JSON模式作为数据传递给Actix Web?