函数局部变量的寿命不够长

时间:2017-05-17 02:14:43

标签: rust serde serde-json

我正在尝试围绕serde_json和amp;写一个包装器。 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>

1 个答案:

答案 0 :(得分:1)

根据@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到临时ResponseJSON返回的rocket::data::Outcome;所以看起来还不错。

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

虽然不是100%肯定我的解释,但是会喜欢你对此的看法