İlişkili bir türü, daha üst sıralarda yer alan bir özellik bağlantılı özellikten nasıl döndürürüm?


11

İlişkili bir türün serileştirilmesi için bir işlevi olan bir özelliği var. Bununla birlikte, ilişkili tür, arayanın karar vereceği bir ömre sahip olmalıdır, bu nedenle, herhangi bir ömür boyu serileştirilebilmesi için bağlı bir üst düzey özellik kullandığım ayrı bir özelliğe sahibim.

Bu ilişkili türü döndüren bir kapatma kullanmanız gerekir.

Bunu yapmak için aşağıdaki kod var:

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

Bu çalışması gerektiğini düşünüyorum, ama ben kontrol ederken bir tür hata alıyorum:

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

Kafa karıştırıcı çünkü kapanıştan geri döndüğüm MyEndpoint::Outbir a MyEndpointBody, ama Rust aynı tür olduklarını düşünmüyor. Sanırım Rust, MyEndpointBodytip için uyumsuz anonim yaşamları seçtiği için , ancak bunu nasıl düzelteceğimi bilmiyorum.

HRTB ile ilişkili tipte bir kapatma kullanabilmem için bu kodu nasıl çalıştırabilirim?

Yanıtlar:


4

Kapanışın dönüş türünü yeni bir türe sarması sorunu giderir:

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

Bu yeni tipin ilişkili türle hemen hemen aynı olması gerektiğini düşünerek, bu bir Rust derleyici hatası olduğunu söylemek cazipim. HRTB ile ilişkili türlerin kullanımı ile ilgili bazı ICE'ler de var gibi görünüyor: https://github.com/rust-lang/rust/issues/62529


0

Eğer kontrol misiniz o birini

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

Bu Fnparametrenin genelleştirilmiş bir çözümü olmayabilir, çünkü parametresinin keyfi bir ömrü olması gerekir. Ama burada bu yaşam bağımlı hale geliyor ve bu tür bir kullanımı imkansız hale getiriyor, lütfen kontrol edin: play.rust-lang.org/…
Ömer Erden

Ne yazık ki bu basit örnekle çalışırken, projem için sahip olduğum kodla çalışmaz. Ne yaptığımı daha iyi göstermek için örneğimi güncelleyeceğim.
Albay Otuz İki

0

Olarak tanımla DeserializeBody:

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

Outgenel bir tür bildirimidir. Burada ömür boyu bağlı beyan etmeyin, tanım sitesinde açık olacaktır.

Bu noktada, Yüksek Sıra Özellik Sınırına artık gerek yoktur Endpoint:

trait Endpoint: DeserializeBody {}

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

Tanımlama yerinde ilişkili tip için bir ömür boyu gereklilikler ifade edilmelidir Out. Daha DeserializeBodygenel değilse o MyEndpointzaman:

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

    ...

Ve böyle bir gereksinimi uygulamak, ömür boyu gerektiren bir hayalet tipe başvurmaya izin verir 'a.

Tüm parçaları bir araya getirmek:

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

Hayır! Bu durumda MyEndpointBodyödünç alınamaz raw_body, çünkü 'aoutlives'in raw_bodyanonim ömrü. HRTB'nin tüm raw_bodyamacı 'aömür boyu vermektir .
Albay Otuz İki

Ah anlıyorum. HRTB ile herhangi bir ömür boyu serileştirmeye ve bundan sonra girdi verilerinden ödünç almaya çalışıyorsunuz. Derleyicinin bir sınırlaması gibi görünen bir kısmı, çözümünüze benzeyen serde :: DeserializeOwned ve serde implerializatörden herhangi bir veri ödünç alamaz.
attdona

Olmalı Bu geçici çözüm sizin için çalışıyor? Vec<u8>bir yere tahsis edilmesi gerekir: tahsisi aşağıya taşır deserialize.
attdona

Evet Eh, olabilir Pes edip ömrünü kaldırmak, ancak o zaman sıfır kopya deserialization olamaz ve söz noktasına yendi.
Albay Otuz İki

0

Sorun, işleyicilerinizin HK kısıtlamasıyla tüm olası yaşamları idare edebilmesini istemenizdir - derleyicinin kanıtlayamadığı, dolayısıyla denkliği yapamayacağınızdır MyEndpointBody <=> MyEndpoint::Out.

Bunun yerine, işleyicilerinizi tek bir kullanım ömrü için parametrelendirirseniz, gerektiği gibi derleniyor ( oyun alanı bağlantısı ):

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

İlk paragrafınızı anlamıyorum. Örneğin, for<'a> Fn(&'a [u8]) -> &'a [u8]gayet iyi yapabilirsiniz ve derleyici bunu kabul edecektir. Soruna neden olan ilişkili tür geri döndüğünde.
Albay Otuz İki

Demek istediğim, mümkünFnHandler olan her yaşam için bir şey döndüren bir işlev alır . Herhangi bir ömür boyu 'a, her zaman aynı olacaktır (a Vec<u8>), ancak bunu bilmiyorsanız, bu çıktı 'aişlevi parametreleştiren yaşam süresine bağlı olabilir . Bu fonksiyonun evrendeki tüm yaşamlar için (muhtemelen yaşam boyu bağımlı) türünü döndürmesini istemek muhtemelen derleyiciyi şaşırtan şeydir: 'kısıtlamayı' kırmadan ve kısıtınızın aslında yaşam boyu bağımlı olmadığını bilerek bu kısıtlamayı doğrulayamazsınız .
val

Durum böyle değil, cevabımdaki newtype sarıcı olarak görmek, ilişkili türü kullanırken iyi çalışıyor. Farklı yaşamlar için farklı ilişkili türlere sahip olabileceğinizi düşünmüyorum; impls koymak zorunda olduğunuz global kapsamda kullanılabilir olan tek adlandırılmış ömür 'static, farklı yaşamlar için bir şeyler nasıl uygularsınız?
Albay Otuz İki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.