2017-10-01 24 views
10

एक प्रोजेक्ट में जहां कस्टम सर्डे (1.0) क्रमबद्धता और deserialization विधियां शामिल हैं, मैंने इस परीक्षण दिनचर्या पर भरोसा किया है कि यह जांचने के लिए कि किसी ऑब्जेक्ट को क्रमबद्ध करना और पीछे बराबर वस्तु उत्पन्न होगी या नहीं।सर्डे क्रमिकरण और deserialization की जांच के लिए हम एक सामान्य कार्य कैसे लिख सकते हैं?

// let o: T = ...; 
let buf: Vec<u8> = to_vec(&o).unwrap(); 
let o2: T = from_slice(&buf).unwrap(); 
assert_eq!(o, o2); 

इस इनलाइन को बहुत अच्छी तरह से काम करता है। पुन: प्रयोज्यता के लिए मेरा अगला कदम इस उद्देश्य के लिए check_serde फ़ंक्शन बनाना था।

pub fn check_serde<T>(o: T) 
where 
    T: Debug + PartialEq<T> + Serialize + DeserializeOwned, 
{ 
    let buf: Vec<u8> = to_vec(&o).unwrap(); 
    let o2: T = from_slice(&buf).unwrap(); 
    assert_eq!(o, o2); 
} 

इस प्रकार के मालिक के लिए अच्छी तरह से काम करता है, लेकिन जीवन सीमा के साथ प्रकार के लिए नहीं (Playground):

check_serde(5); 
check_serde(vec![1, 2, 5]); 
check_serde("five".to_string()); 
check_serde("wait"); // [E0279] 

त्रुटि:

error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) 
    --> src/main.rs:24:5 
    | 
24 |  check_serde("wait"); // [E0277] 
    |  ^^^^^^^^^^^ 
    | 
    = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str` 
    = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `&str` 
    = note: required by `check_serde` 

मैं समारोह काम करना चाहते हैं के रूप में इन मामलों के साथ (स्ट्रिंग स्लाइस के साथ structs सहित), मैंने एक स्पष्ट वस्तु deserialization जीवनकाल के साथ एक नया संस्करण का प्रयास किया:

pub fn check_serde<'a, T>(o: &'a T) 
where 
    T: Debug + PartialEq<T> + Serialize + Deserialize<'a>, 
{ 
    let buf: Vec<u8> = to_vec(o).unwrap(); 
    let o2: T = from_slice(&buf).unwrap(); 
    assert_eq!(o, &o2); 
} 

check_serde(&5); 
check_serde(&vec![1, 2, 5]); 
check_serde(&"five".to_string()); 
check_serde(&"wait"); // [E0405] 

यह कार्यान्वयन एक और मुद्दा की ओर जाता है, और यह संकलित नहीं होगा (Playground)।

error[E0597]: `buf` does not live long enough 
    --> src/main.rs:14:29 
    | 
14 |  let o2: T = from_slice(&buf).unwrap(); 
    |        ^^^ does not live long enough 
15 |  assert_eq!(o, &o2); 
16 | } 
    | - borrowed value only lives until here 
    | 
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 10:1... 
    --> src/main.rs:10:1 
    | 
10 |/pub fn check_serde<'a, T>(o: &'a T) 
11 | |  where T: Debug + PartialEq<T> + Serialize + Deserialize<'a> 
12 | | { 
13 | |  let buf: Vec<u8> = to_vec(o).unwrap(); 
14 | |  let o2: T = from_slice(&buf).unwrap(); 
15 | |  assert_eq!(o, &o2); 
16 | | } 
    | |_^ 

मैं पहले से ही इस एक की उम्मीद है: इस संस्करण का तात्पर्य है कि धारावाहिक सामग्री (और इसलिए deserialized वस्तु) के रूप में लंबे समय तक रहता है इनपुट वस्तु है, जो सच नहीं है के रूप में। बफर केवल कार्य के दायरे तक जीने के लिए है।

मेरा तीसरा प्रयास मूल इनपुट के स्वामित्व वाले संस्करणों का निर्माण करना चाहता है, इस प्रकार विभिन्न आजीवन सीमाओं के साथ एक deserialized वस्तु होने के मुद्दे को बचाना। इस उपयोग मामले के अनुरूप ToOwned विशेषता दिखाई देती है।

pub fn check_serde<'a, T: ?Sized>(o: &'a T) 
where 
    T: Debug + ToOwned + PartialEq<<T as ToOwned>::Owned> + Serialize, 
    <T as ToOwned>::Owned: Debug + DeserializeOwned, 
{ 
    let buf: Vec<u8> = to_vec(&o).unwrap(); 
    let o2: T::Owned = from_slice(&buf).unwrap(); 
    assert_eq!(o, &o2); 
} 

यह अब सादे स्ट्रिंग स्लाइस के लिए समारोह काम करता है, लेकिन समग्र वस्तुओं के लिए उन्हें शामिल नहीं (Playground):

check_serde(&5); 
check_serde(&vec![1, 2, 5]); 
check_serde(&"five".to_string()); 
check_serde("wait"); 
check_serde(&("There's more!", 36)); // [E0279] 

फिर, हम पहले संस्करण के रूप में ही त्रुटि प्रकार पर आते हैं:

error[E0279]: the requirement `for<'de> 'de : ` is not satisfied (`expected bound lifetime parameter 'de, found concrete lifetime`) 
    --> src/main.rs:25:5 
    | 
25 |  check_serde(&("There's more!", 36)); // [E0279] 
    |  ^^^^^^^^^^^ 
    | 
    = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `&str` 
    = note: required because of the requirements on the impl of `for<'de> serde::Deserialize<'de>` for `(&str, {integer})` 
    = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `(&str, {integer})` 
    = note: required by `check_serde` 

अनुमोदित, मुझे नुकसान हुआ है। हम एक जेनेरिक फ़ंक्शन कैसे बना सकते हैं, जो सेर्डे का उपयोग करते हुए, किसी ऑब्जेक्ट को क्रमबद्ध करता है और उसे वापस एक नई वस्तु में deserializes? विशेष रूप से, क्या यह कार्य जंग (स्थिर या रात में) में किया जा सकता है, और यदि हां, तो मेरे कार्यान्वयन में कौन से समायोजन गुम हैं?

उत्तर

5

दुर्भाग्य से, क्या आप की जरूरत एक फीचर था है टी अभी तक जंग में लागू नहीं किया गया है: जेनेरिक जुड़े प्रकार।

के check_serde का एक अलग संस्करण पर नजर डालते हैं:

pub fn check_serde<T>(o: T) 
where 
    for<'a> T: Debug + PartialEq<T> + Serialize + Deserialize<'a>, 
{ 
    let buf: Vec<u8> = to_vec(&o).unwrap(); 
    let o2: T = from_slice(&buf).unwrap(); 
    assert_eq!(o, o2); 
} 

fn main() { 
    check_serde("wait"); // [E0279] 
} 

समस्या है कि यहाँ o2 प्रकार T के नहीं किया जा सकता है: o2, buf को संदर्भित करता है जो एक स्थानीय चर रहा है, लेकिन प्रकार पैरामीटर के लिए नहीं लगाया जा सकता जीवन भर से बाधित प्रकार जो कि कार्य के शरीर तक ही सीमित है। हम T&str के साथ कुछ विशिष्ट जीवनकाल के बिना कुछ ऐसा होना चाहते हैं।

trait SerdeFamily { 
    type Member<'a>: Debug + PartialEq<Self> + Serialize + Deserialize<'a>; 
} 

struct I32Family; 
struct StrFamily; 

impl SerdeFamily for I32Family { 
    type Member<'a> = i32; // we can ignore parameters 
} 

impl SerdeFamily for StrFamily { 
    type Member<'a> = &'a str; 
} 

pub fn check_serde<'a, Family>(o: Family::Member<'a>) 
where 
    Family: SerdeFamily, 
{ 
    let buf: Vec<u8> = to_vec(&o).unwrap(); 
    // `o2` is of type `Family::Member<'b>` 
    // with a lifetime 'b different from 'a 
    let o2: Family::Member = from_slice(&buf).unwrap(); 
    assert_eq!(o, o2); 
} 

fn main() { 
    check_serde::<I32Family>(5); 
    check_serde::<StrFamily>("wait"); 
} 
:

सामान्य जुड़े प्रकार के साथ, यह (जाहिर है मैं, यह परीक्षण नहीं कर सकते, क्योंकि यह अभी तक लागू नहीं किया गया है) कुछ इस तरह से हल किया जा सकता

3

answer from Francis Gagné दिखाया गया है कि हम सामान्य रूप से सामान्य प्रकार के बिना कुशलता से ऐसा नहीं कर सकते हैं। Deserialized वस्तु के गहरे स्वामित्व की स्थापना एक संभावित काम है जिसके आसपास मैं वर्णन करता हूं।

तीसरा प्रयास एक लचीला समाधान के बहुत करीब है, लेकिन यह std::borrow::ToOwned काम करता है के कारण यह कम हो जाता है। विशेषता किसी वस्तु के गहरे स्वामित्व वाले संस्करण को पुनर्प्राप्त करने के लिए उपयुक्त नहीं है। उदाहरण के लिए, &str के लिए ToOwned के कार्यान्वयन का उपयोग करने का प्रयास, आपको एक और स्ट्रिंग स्लाइस देता है।

let a: &str = "hello"; 
let b: String = (&a).to_owned(); // expected String, got &str 

इसी तरह, एक struct युक्त स्ट्रिंग स्लाइस के लिए Owned प्रकार String रों युक्त एक struct नहीं हो सकता। कोड में:

#[derive(Debug, PartialEq, Serialize, Deserialize)] 
struct Foo<'a>(&str, i32); 

#[derive(Debug, PartialEq, Serialize, Deserialize)] 
struct FooOwned(String, i32); 

हम Foo के लिए ToOwned Impl नहीं कर सकते हैं प्रदान करने के लिए FooOwned है क्योंकि:

  • अगर हम Clone निकाले जाते हैं, T: Clone के लिए ToOwned के कार्यान्वयन केवल Owned = Self लिए लागू है।
  • ToOwned के कस्टम कार्यान्वयन के साथ भी, इस विशेषता के लिए आवश्यक है कि स्वामित्व वाले प्रकार को मूल प्रकार में उधार लिया जा सके (बाधा Owned: Borrow<Self> की वजह से)। यही है, हम FooOwned में से &Foo(&str, i32) पुनर्प्राप्त करने में सक्षम होना चाहिए, लेकिन उनकी आंतरिक संरचना अलग है, और इसलिए यह प्राप्य नहीं है।

इसका मतलब है कि, तीसरे दृष्टिकोण का पालन करने के लिए, हमें एक अलग विशेषता की आवश्यकता है। आइए एक नई विशेषता ToDeeplyOwned है जो ऑब्जेक्ट को पूरी तरह से स्वामित्व में बदल देती है, जिसमें कोई स्लाइस या संदर्भ शामिल नहीं है।

pub trait ToDeeplyOwned { 
    type Owned; 
    fn to_deeply_owned(&self) -> Self::Owned; 
} 

यहां इरादा किसी भी चीज़ से गहरी प्रतिलिपि बनाना है। ऐसा लगता है कि एक आसान पकड़ नहीं है - सभी कार्यान्वयन, लेकिन कुछ चाल संभव हैं। सबसे पहले, हम इसे सभी संदर्भ प्रकारों पर लागू कर सकते हैं जहां T: ToDeeplyOwned

impl<'a, T: ?Sized + ToDeeplyOwned> ToDeeplyOwned for &'a T { 
    type Owned = T::Owned; 
    fn to_deeply_owned(&self) -> Self::Owned { 
     (**self).to_deeply_owned() 
    } 
} 

इस बिंदु पर हमें इसे गैर-संदर्भ प्रकारों में चुनिंदा रूप से लागू करना होगा जहां हम जानते हैं कि यह ठीक है। मैंने इस प्रक्रिया को कम वर्बोज़ बनाने के लिए एक मैक्रो लिखा है, जो आंतरिक रूप से to_owned() का उपयोग करता है।

macro_rules! impl_deeply_owned { 
    ($t: ty, $t2: ty) => { // turn $t into $t2 
     impl ToDeeplyOwned for $t { 
      type Owned = $t2; 
      fn to_deeply_owned(&self) -> Self::Owned { 
       self.to_owned() 
      } 
     } 
    }; 
    ($t: ty) => { // turn $t into itself, self-contained type 
     impl ToDeeplyOwned for $t { 
      type Owned = $t; 
      fn to_deeply_owned(&self) -> Self::Owned { 
       self.to_owned() 
      } 
     } 
    }; 
} 

प्रश्न में उदाहरण के लिए काम करने के लिए, हम कम से कम इन की जरूरत है:

impl_deeply_owned!(i32); 
impl_deeply_owned!(String); 
impl_deeply_owned!(Vec<i32>); 
impl_deeply_owned!(str, String); 

एक बार जब हम Foo/FooOwned पर आवश्यक लक्षण को लागू करने और serde_check अनुकूलन नई विशेषता का उपयोग करने, कोड अब संकलित करता है तथा सफलतापूर्वक चलता (Playground):

#[derive(Debug, PartialEq, Serialize)] 
struct Foo<'a>(&'a str, i32); 

#[derive(Debug, PartialEq, Clone, Deserialize)] 
struct FooOwned(String, i32); 

impl<'a> ToDeeplyOwned for Foo<'a> { 
    type Owned = FooOwned; 

    fn to_deeply_owned(&self) -> FooOwned { 
     FooOwned(self.0.to_string(), self.1) 
    } 
} 

impl<'a> PartialEq<FooOwned> for Foo<'a> { 
    fn eq(&self, o: &FooOwned) -> bool { 
     self.0 == o.0 && self.1 == o.1 
    } 
} 

pub fn check_serde<'a, T: ?Sized>(o: &'a T) 
where 
    T: Debug + ToDeeplyOwned + PartialEq<<T as ToDeeplyOwned>::Owned> + Serialize, 
    <T as ToDeeplyOwned>::Owned: Debug + DeserializeOwned, 
{ 
    let buf: Vec<u8> = to_vec(&o).unwrap(); 
    let o2: T::Owned = from_slice(&buf).unwrap(); 
    assert_eq!(o, &o2); 
} 

// all of these are ok 
check_serde(&5); 
check_serde(&vec![1, 2, 5]); 
check_serde(&"five".to_string()); 
check_serde("wait"); 
check_serde(&"wait"); 
check_serde(&Foo("There's more!", 36)); 
संबंधित मुद्दे