2017-05-17 9 views
2

私はserde_jsonのラッパーを書こうとしています& RocketのFromDataは、サーバーと交換するJSON Iの一部を強く入力します。関数のローカル変数が十分に長生きしていません

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!"); 
} 

コンパイラのエラー:私は次のコードをコンパイルすることはできません

data_from_reader以来

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 

を、valueunwraped_valuedataから来た私は、コンパイラはそれがあったことを推測することができると思いました同じ生涯が、明らかにそうではありません。そのような場合には、私がそれを述べたり、何かすることができる方法はありますか?

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:上記@LukasKalbertodtのコメントを1として

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

について自分の考えを大好きだ、私のexplainationの100%を確認してくださいしかし、あなたの問題は、おそらくに沸く:[機能で作成した変数への参照を返すためにどのような方法がありますか?](HTTP ://stackoverflow.com/questions/32682876/is-there-any-way-to-return-a-reference-to-a-variable-created-in-a-function/32683309#32683309)答えは次のとおりです基本的にはありません。あなたの 'ResponseJson'はそれを借りる代わりに' serde_json :: Value'を所有する必要があります。あなたが時々借りたい、時にはそれを所有している場合は、['Cow'](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html)に興味があるかもしれません。 –

+0

@LukasKalbertodtそこに行く。最初の行が見つかりません。 Trait(その場合はFormData)を実装するために、関数で作成された変数への参照を返すことに変わりはありません。変わったのは、私が基本的に新しく作成したResponseJSONを返すので、 'from_serde_value(&Value)'関数でそれを処理できることです。'from_data()'関数の場合にはあまり変わらないと思っていました – Boris

+0

@LukasKalbertodtの提案によれば、ResponseJSONが 'serde_json :: Value'を所有していればコンパイルされます(構造体定義と関数シグネチャの中のすべての参照を削除します)。ディスカッション/アーカイブのための答えとしてそれを追加する – Boris

答えて

0

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;だから大丈夫だと思う。

参考文献では、tempJ ResponseJSONは、それが作成されたserde_json::Value、つまり寿命が0​​であり、寿命が機能の終了よりも長かったため、関数の終了よりも長生きしませんでした。したがってコンパイラの問題です。

していないが、その

関連する問題