উচ্চ-র‌্যাঙ্কযুক্ত বৈশিষ্ট্যযুক্ত বাউন্ড বৈশিষ্ট্য থেকে আমি কীভাবে সম্পর্কিত প্রকারটি ফিরিয়ে দেব?


11

আমার একটি বৈশিষ্ট্য রয়েছে যা সম্পর্কিত কোনও ধরণের ডিজাইরিজাইজ করার জন্য একটি ফাংশন রাখে। তবে সম্পর্কিত সম্পর্কিতটির জন্য কলার সিদ্ধান্ত নেয় এমন একটি আজীবন প্রয়োজন, সুতরাং আমার একটি পৃথক বৈশিষ্ট্য রয়েছে যা আমি উচ্চতর-র‌্যাঙ্কযুক্ত বৈশিষ্ট্যের জন্য আবদ্ধ থাকি, যাতে এটি কোনও জীবনকালের জন্য বিশৃঙ্খলাবদ্ধ হতে পারে।

আমাকে এমন একটি ক্লোজার ব্যবহার করতে হবে যা এই সম্পর্কিত ধরণটি দেয়।

এটি করার জন্য আমার কাছে নিম্নলিখিত কোড রয়েছে:

#![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টাইপের জন্য বেমানান বেনামে জীবনকাল বেছে নিয়েছে , তবে কীভাবে এটি ঠিক করতে হয় তা আমি জানি না।

আমি এই কোডটি কীভাবে কাজ করতে পারি যাতে আমি এইচআরটিবি সম্পর্কিত ধরণের সাথে ক্লোজারটি ব্যবহার করতে পারি?

উত্তর:


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(&[]);
}

নতুন প্রকারটি সম্পর্কিত ধরণের মতোই হওয়া উচিত বলে বিবেচনা করে আমি এটি একটি মরিচা সংকলক বাগ বলে প্ররোচিত করছি। এছাড়াও এইচআরটিবি সম্পর্কিত ধরণের ব্যবহার সম্পর্কিত কিছু আইসিই রয়েছে বলে মনে হয়: 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/...
Ömer 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
কর্নেল থার্টি টু

আচ্ছা বুঝলাম. এইচআরটিবি দিয়ে আপনি যেকোন আজীবন ডিসরিয়ালাইজ করার চেষ্টা করছেন এবং এরপরে ইনপুট ডেটা থেকে orrowণ নেওয়ার চেষ্টা করছেন। একটি অংশ যা সংকলকটির সীমাবদ্ধতা বলে মনে হচ্ছে, আপনার সমাধানটি সারডের মতো দেখায়: DeserializeOwned এবং serde impl deserializer থেকে কোনও ডেটা ধার নিতে পারে না।
এটডোনা

উচিত এই কার্যসংক্রান্ত আপনার জন্য কাজ করে? Vec<u8>কোথাও বরাদ্দ করা দরকার: বরাদ্দটি নীচে সরানো হয় deserialize
এটডোনা

আচ্ছা হ্যাঁ, আমি কেবল আজীবন ছেড়ে দিয়ে জীবনকাল সরিয়ে ফেলতে পারতাম , তবে তারপরে আমার শূন্য-অনুলিপি বিশৃঙ্খলা থাকতে পারে না এবং এটি প্রশ্নের বিন্দুটিকে পরাস্ত করে।
কর্নেল তিরিশ দুই

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আংশিক ক্রিয়াটি প্যারামিটারাইজিংয়ের উপর নির্ভর করবে। যে ফাংশন অনুরোধ করা হচ্ছে যে (সম্ভবত জীবনকাল নির্ভর) টাইপ ফিরে যাওয়ার মহাবিশ্বের সব জীবনকালের জন্য কি কম্পাইলার বিভ্রান্ত সম্ভবত হল: আপনি ছাড়া 'এলাকার ভঙ্গ' এবং বুদ্ধিমান যে আপনার বাধ্যতা আসলে এই বাধ্যতা যাচাই করতে পারে না না জীবদ্দশায় নির্ভরশীল।
Val

এটি ক্ষেত্রে নয়, সম্পর্কিত উত্তরটি ব্যবহার করার সময় আমার উত্তরটিতে নতুন টাইপের মোড়ক ঠিক ঠিক কাজ করে। আমি মনে করি না যে আপনি বিভিন্ন লাইফটাইমের জন্য আলাদা আলাদা প্রকারের থাকতেও পারেন; বিশ্বব্যাপী সুযোগে পাওয়া একমাত্র নামকৃত জীবনকাল যেখানে আপনাকে ইমপ্লস করতে হবে তা হ'ল 'staticআপনি কীভাবে বিভিন্ন জীবনকালীন সময়ে জিনিসপত্র বাস্তবায়ন করবেন?
কর্নেল থার্টি টু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.