मैं एक उच्च श्रेणी की विशेषता सीमा से संबंधित प्रकार कैसे वापस करूं?


11

मेरे पास एक विशेषता है जो एक संबद्ध प्रकार के deserializing के लिए एक फ़ंक्शन है। हालाँकि, उस संबद्ध प्रकार को आजीवन रहने की आवश्यकता होती है, जिसे कॉल करने वाला तय करता है, इसलिए मेरे पास एक अलग विशेषता है कि मैं उच्च श्रेणी के लिए बाध्य विशेषता का उपयोग करता हूं, ताकि यह किसी भी जीवनकाल के लिए निर्जन हो सके।

मुझे एक क्लोजर का उपयोग करने की आवश्यकता है जो इस संबद्ध प्रकार को वापस करता है।

मेरे पास ऐसा करने के लिए निम्नलिखित कोड है:

#![allow(unreachable_code)]

use std::marker::PhantomData;

trait Endpoint: for<'a> EndpointBody<'a> {}
trait EndpointBody<'a> {
    type Out: 'a;
    fn serialize(body: &Self::Out) -> Vec<u8>;
    fn deserialize(raw_body: &'a [u8]) -> Self::Out;
}

// /////////////////////////////////////////////////////////

/// Trait object compatible handler
trait Handler {
    fn execute(&self, raw_body: &[u8]) -> Vec<u8>;
}

/// Wraps a function for an endpoint, convertint it to a Handler
struct FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
{
    func: F,
    _ph: PhantomData<EP>,
}
impl<EP, F> FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
{
    pub fn new(func: F) -> Self {
        Self {
            func,
            _ph: PhantomData,
        }
    }
}
impl<EP, F> Handler for FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
{
    fn execute(&self, in_raw_body: &[u8]) -> Vec<u8> {
        let body = (self.func)(in_raw_body);
        let serialized_body = unimplemented!();
        return serialized_body;
    }
}

// /////////////////////////////////////////////////////////

/// Collection of handlers
struct Handlers(Vec<Box<dyn Handler>>);
impl Handlers {
    pub fn new() -> Self {
        Self(vec![])
    }

    pub fn handle<EP: 'static, F>(&mut self, func: F)
    where
        EP: Endpoint,
        F: 'static + for<'a> Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
    {
        self.0.push(Box::new(FnHandler::<EP, F>::new(func)));
    }
}

// /////////////////////////////////////////////////////////

struct MyEndpoint;
struct MyEndpointBody<'a> {
    pub string: &'a str,
}
impl Endpoint for MyEndpoint {}
impl<'a> EndpointBody<'a> for MyEndpoint {
    type Out = MyEndpointBody<'a>;

    fn serialize(body: &Self::Out) -> Vec<u8> {
        unimplemented!()
    }
    fn deserialize(raw_body: &'a [u8]) -> Self::Out {
        unimplemented!()
    }
}

// /////////////////////////////////////////////////////////

fn main() {
    let mut handlers = Handlers::new();
    handlers.handle::<MyEndpoint, _>(|_body| MyEndpointBody {
        string: "test string",
    });

    handlers.0[1].execute(&[]);
}

मुझे लगता है कि काम करना चाहिए, लेकिन जब मैं इसकी जांच करता हूं तो मुझे एक प्रकार की त्रुटि मिलती है:

error[E0271]: type mismatch resolving `for<'a> <[closure@src/main.rs:92:38: 94:6] as std::ops::FnOnce<(&'a [u8],)>>::Output == <MyEndpoint as EndpointBody<'a>>::Out`
  --> src/main.rs:92:14
   |
92 |     handlers.handle::<MyEndpoint, _>(|_body| MyEndpointBody {
   |              ^^^^^^ expected struct `MyEndpointBody`, found associated type
   |
   = note:       expected struct `MyEndpointBody<'_>`
           found associated type `<MyEndpoint as EndpointBody<'_>>::Out`
   = note: consider constraining the associated type `<MyEndpoint as EndpointBody<'_>>::Out` to `MyEndpointBody<'_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

यह भ्रामक है क्योंकि MyEndpoint::Outएक है MyEndpointBody, जिसे मैं बंद करने से लौट रहा हूं, लेकिन रस्ट को नहीं लगता कि वे एक ही प्रकार हैं। मैं यह अनुमान लगा रहा हूं क्योंकि रस्ट MyEndpointBodyटाइप के लिए असंगत अनाम जीवनकाल उठाता है , लेकिन मुझे नहीं पता कि इसे कैसे ठीक किया जाए।

मुझे यह कोड काम करने के लिए कैसे मिल सकता है ताकि मैं HRTB से जुड़े प्रकार के साथ एक क्लोजर का उपयोग कर सकूं?

जवाबों:


4

क्लोजर रैप को एक न्यूटाइप में लपेटने से समस्या ठीक हो जाती है:

#![allow(unreachable_code)]

use std::marker::PhantomData;

trait Endpoint: for<'a> EndpointBody<'a> {}
trait EndpointBody<'a> {
    type Out: 'a;
    fn serialize(body: &Self::Out) -> Vec<u8>;
    fn deserialize(raw_body: &'a [u8]) -> Self::Out;
}

struct EPOut<'a, EP: Endpoint>(<EP as EndpointBody<'a>>::Out);

// /////////////////////////////////////////////////////////

/// Trait object compatible handler
trait Handler {
    fn execute(&self, raw_body: &[u8]) -> Vec<u8>;
}

/// Wraps a function for an endpoint, convertint it to a Handler
struct FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> EPOut<'a, EP>,
{
    func: F,
    _ph: PhantomData<EP>,
}
impl<EP, F> FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> EPOut<'a, EP>,
{
    pub fn new(func: F) -> Self {
        Self {
            func,
            _ph: PhantomData,
        }
    }
}
impl<EP, F> Handler for FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> EPOut<'a, EP>,
{
    fn execute(&self, in_raw_body: &[u8]) -> Vec<u8> {
        let body = (self.func)(in_raw_body);
        let serialized_body = unimplemented!();
        return serialized_body;
    }
}

// /////////////////////////////////////////////////////////

/// Collection of handlers
struct Handlers(Vec<Box<dyn Handler>>);
impl Handlers {
    pub fn new() -> Self {
        Self(vec![])
    }

    pub fn handle<EP: 'static, F>(&mut self, func: F)
    where
        EP: Endpoint,
        F: 'static + for<'a> Fn(&'a [u8]) -> EPOut<'a, EP>,
    {
        self.0.push(Box::new(FnHandler::<EP, F>::new(func)));
    }
}

// /////////////////////////////////////////////////////////

struct MyEndpoint;
struct MyEndpointBody<'a> {
    pub string: &'a str,
}
impl Endpoint for MyEndpoint {}
impl<'a> EndpointBody<'a> for MyEndpoint {
    type Out = MyEndpointBody<'a>;

    fn serialize(body: &Self::Out) -> Vec<u8> {
        unimplemented!()
    }
    fn deserialize(raw_body: &'a [u8]) -> Self::Out {
        unimplemented!()
    }
}

// /////////////////////////////////////////////////////////

fn main() {
    let mut handlers = Handlers::new();
    handlers.handle::<MyEndpoint, _>(|_body| EPOut(MyEndpointBody {
        string: "test string",
    }));

    handlers.0[1].execute(&[]);
}

मुझे यह कहते हुए ललचाया जा रहा है कि यह एक रस्ट कंपाइलर बग है, यह देखते हुए कि न्यूटाइप केवल संबंधित प्रकार के समान होना चाहिए। HRTB से जुड़े प्रकारों के उपयोग से संबंधित कुछ ICE भी प्रतीत होते हैं: https://github.com/rust-lang/rust/issues/62529


0

क्या आप कृपया जाँच सकते हैं कि एक

trait Endpoint: for<'a> DeserializeBody<'a> {}
trait DeserializeBody<'a> {
    type Out: 'a;
    fn deserialize(raw_body: &'a [u8]) -> Self::Out;
}

fn store_ep<'a, EP, F>(func: F)
where
    EP: Endpoint,
    F: 'static + Fn(&'a [u8]) -> <EP as DeserializeBody<'a>>::Out,
{
    let _ = Box::new(func);
    unimplemented!();
}

// /////////////////////////////////////////////////////////

struct MyEndpoint;
struct MyEndpointBody<'a> {
    pub string: &'a str,
}
impl Endpoint for MyEndpoint {}
impl<'a> DeserializeBody<'a> for MyEndpoint {
    type Out = MyEndpointBody<'a>;
    fn deserialize(raw_body: &'a [u8]) -> Self::Out {
        unimplemented!();
    }
}

// /////////////////////////////////////////////////////////

fn main() {
    store_ep::<MyEndpoint, _>(|raw_body| MyEndpointBody { string: "test" });
}

यह एक सामान्यीकृत समाधान नहीं हो सकता है, क्योंकि Fnपैरामीटर को एक मनमाना जीवनकाल की आवश्यकता होती है। लेकिन यहाँ यह जीवनकाल निर्भर हो जाता है और यह इस तरह के उपयोग को असंभव बना देता है, कृपया देखें: play.rust-lang.org/…
Erden

दुर्भाग्य से जब यह सरल उदाहरण के साथ काम करता है, तो यह मेरे प्रोजेक्ट के लिए मेरे पास कोड के साथ काम नहीं करता है। मैं अपने उदाहरण को बेहतर ढंग से चित्रित करूँगा कि मैं क्या कर रहा हूँ।
कर्नल थर्टी टू

0

इस DeserializeBodyरूप में परिभाषित करें :

trait DeserializeBody {
    type Out;
    fn deserialize(raw_body: &[u8]) -> Self::Out;
}

Outएक सामान्य प्रकार की घोषणा है। यहां आजीवन बाध्य घोषित न करें, यह परिभाषा स्थल पर स्पष्ट होगा।

इस बिंदु पर इसके लिए हायर-रैंक ट्रेल बाउंड आवश्यक नहीं है Endpoint:

trait Endpoint: DeserializeBody {}

trait DeserializeBody {
    type Out;
    fn deserialize(raw_body: &[u8]) -> Self::Out;
}

परिभाषा स्थल पर संबंधित प्रकार के लिए जीवन भर की आवश्यकताओं को व्यक्त किया जाना चाहिए Out। यदि DeserializeBodyअधिक सामान्य नहीं है तो MyEndpointहोना चाहिए:

impl<'a> DeserializeBody for MyEndpoint<'a> {
    type Out = MyEndpointBody<'a>;

    ...

और ऐसी आवश्यकता को लागू करने के लिए एक प्रेत प्रकार का सहारा लेना पड़ता है, जिसे जीवन भर की आवश्यकता होती है 'a

सभी टुकड़ों को एक साथ रखना:

use core::marker::PhantomData;

trait Endpoint: DeserializeBody {}

trait DeserializeBody {
    type Out;
    fn deserialize(raw_body: &[u8]) -> Self::Out;
}

fn store_ep<EP, F>(func: F)
where
    EP: Endpoint,
    F: 'static + for<'a> Fn(&'a [u8]) -> <EP as DeserializeBody>::Out,
{
    let _ = Box::new(func);
    unimplemented!();
}

struct MyEndpoint<'a> {
    phantom: PhantomData<&'a ()>
}

struct MyEndpointBody<'a> {
    pub string: &'a str,
}

impl<'a> Endpoint for MyEndpoint<'a> {}

impl<'a> DeserializeBody for MyEndpoint<'a> {
    type Out = MyEndpointBody<'a>;

    fn deserialize(raw_body: &[u8]) -> Self::Out {
        unimplemented!();
    }
}

fn main() {
    store_ep::<MyEndpoint, _>(|raw_body| MyEndpointBody { string: "test" });
}

नहीं। MyEndpointBodyसे उधार नहीं कर सकते raw_body, उस मामले में, क्योंकि 'aबाद भी जीवित रहता raw_bodyहै गुमनाम जीवन भर। HRTB का संपूर्ण बिंदु जीवनकाल देना raw_bodyहै 'a
कर्नल थर्टी टू

ओह मैं समझा। HRTB के साथ आप किसी भी आजीवन के लिए deserialize करने की कोशिश कर रहे हैं, और उसके बाद इनपुट डेटा से उधार लेने के लिए। एक हिस्सा जो संकलक की एक सीमा लगता है, जो आपके समाधान की तरह दिखता है वह है serde :: DeserializeOwned और serde impl यह deserializer से कोई डेटा उधार नहीं ले सकता है।
एटनडोना

क्या यह समाधान आपके लिए काम करना चाहिए ? Vec<u8>कहीं आवंटित करने की आवश्यकता है: आवंटन को नीचे ले जाता है deserialize
attdona

ठीक है, मैं बस जीवनकाल को छोड़ सकता हूं और हटा सकता हूं , लेकिन तब मेरे पास शून्य-प्रतिरूपीकरण नहीं हो सकता है और यह प्रश्न के बिंदु को हरा देता है।
कर्नल थर्टी टू

0

मुझे लगता है कि मुद्दा यह है कि आप अपने हैंडलर्स से अनुरोध करते हैं कि वे उस एचके अड़चन के साथ सभी संभावित जीवनकालों को संभालने में सक्षम हों - जिसे संकलक साबित नहीं कर सकता है, इसलिए समतुल्यता बनाने में सक्षम नहीं है MyEndpointBody <=> MyEndpoint::Out

यदि इसके बजाय, आप अपने हैंडलर को एक जीवनकाल लेने के लिए पैरामीटर करते हैं , तो यह आवश्यक रूप से संकलन करने के लिए प्रकट होता है ( खेल का मैदान लिंक ):

#![allow(unreachable_code)]

use std::marker::PhantomData;

trait Endpoint: for<'a> EndpointBody<'a> {}
trait EndpointBody<'a> {
    type Out: 'a;
    fn serialize(body: &Self::Out) -> Vec<u8>;
    fn deserialize(raw_body: &'a [u8]) -> Self::Out;
}
/// Trait object compatible handler
trait Handler<'a> {
    fn execute(&self, raw_body: &'a [u8]) -> Vec<u8>;
}

/// Wraps a function for an endpoint, convertint it to a Handler
struct FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static,
{
    func: F,
    _ph: PhantomData<EP>,
}
impl<EP, F> FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static,
{
    pub fn new(func: F) -> Self {
        Self {
            func,
            _ph: PhantomData,
        }
    }
}
impl<'a, EP, F> Handler<'a> for FnHandler<EP, F>
where
    EP: Endpoint,
    F: 'static + Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
{
    fn execute(&self, in_raw_body: &'a [u8]) -> Vec<u8> {
        let body = (self.func)(in_raw_body);
        let serialized_body = unimplemented!();
        return serialized_body;
    }
}

// /////////////////////////////////////////////////////////

/// Collection of handlers
struct Handlers<'a>(Vec<Box<dyn Handler<'a>>>);
impl<'a> Handlers<'a> {
    pub fn new() -> Self {
        Self(vec![])
    }

    pub fn handle<EP: 'static, F>(&mut self, func: F)
    where
        EP: Endpoint,
        F: 'static + Fn(&'a [u8]) -> <EP as EndpointBody<'a>>::Out,
    {
        self.0.push(Box::new(FnHandler::<EP, F>::new(func)));
    }
}

// /////////////////////////////////////////////////////////

struct MyEndpoint;
struct MyEndpointBody<'a> {
    pub string: &'a str,
}
impl Endpoint for MyEndpoint {}
impl<'a> EndpointBody<'a> for MyEndpoint {
    type Out = MyEndpointBody<'a>;

    fn serialize(body: &Self::Out) -> Vec<u8> {
        unimplemented!()
    }
    fn deserialize(raw_body: &'a [u8]) -> Self::Out {
        unimplemented!()
    }
}

// /////////////////////////////////////////////////////////

fn main() {
    let mut handlers = Handlers::new();
    handlers.handle::<MyEndpoint, _>(|_body| MyEndpointBody {
        string: "test string",
    });

    handlers.0[1].execute(&[]);
}

मुझे आपका पहला पैराग्राफ समझ नहीं आ रहा है। आप कर सकते हैं, उदाहरण के लिए, for<'a> Fn(&'a [u8]) -> &'a [u8]बस ठीक है, और संकलक इसे स्वीकार करेंगे। यह सिर्फ तब होता है जब संबंधित प्रकार लौटाया जाता है जो समस्या का कारण बनता है।
कर्नल थर्टी टू

मेरा मतलब था कि आपका FnHandlerएक फंक्शन है, जो हर संभव जीवन भर के लिए , कुछ देता है। यह आपके मामले में होता है कि किसी भी जीवनकाल के लिए 'a, यह हमेशा एक ही (ए Vec<u8>) होने वाला है, लेकिन यदि आप यह नहीं जानते हैं, तो यह आउटपुट 'aफ़ंक्शन के पैरामीटर पर आजीवन निर्भर हो सकता है। ब्रह्मांड में सभी जीवन काल के लिए (संभवतः जीवनकाल-निर्भर) प्रकार को वापस करने के लिए उस फ़ंक्शन का अनुरोध करना संभवतः संकलक को भ्रमित करता है: आप इस अवरोध को 'स्थानीयता को तोड़ने' के बिना सत्यापित नहीं कर सकते हैं और यह जानना कि आपका बाधा वास्तव में जीवन भर निर्भर नहीं है।
वैल

ऐसा नहीं है, मेरे जवाब में newtype आवरण के रूप में देखकर संबंधित प्रकार का उपयोग करते समय ठीक काम करता है। मुझे नहीं लगता कि आपके पास विभिन्न जीवनकालों के लिए अलग-अलग प्रकार भी हो सकते हैं; वैश्विक स्तर पर उपलब्ध एकमात्र नाम आजीवन, जहां आपको इंप्लांट लगाना है, 'staticतो आप विभिन्न जीवन काल के लिए सामान कैसे लागू करेंगे?
कर्नल थर्टी दो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.