상위 순위 특성 바인딩 특성에서 관련 유형을 어떻게 반환합니까?


11

관련 형식을 deserialize하는 기능이있는 특성이 있습니다. 그러나 관련 유형에는 발신자가 결정한 수명이 필요하므로 상위 특성을 사용하는 별도의 특성이 있으므로 평생 동안 직렬화를 해제 할 수 있습니다.

이 관련 유형을 반환하는 클로저를 사용해야합니다.

이를 수행하기 위해 다음 코드가 있습니다.

#![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::OutA는 MyEndpointBody내가 폐쇄에서 복귀하고있는, 그러나 녹들은 같은 종류 생각하지 않습니다. Rust가 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(&[]);
}

나는 이것이 새로운 유형이 관련 유형과 거의 같아야한다는 것을 고려할 때 이것이 Rust 컴파일러 버그라고 말하고 싶습니다. 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/…
Ömer Erden

불행히도 이것은 간단한 예제와 함께 작동하지만 내 프로젝트의 코드에서는 작동하지 않습니다. 내가하고있는 일을 더 잘 설명하기 위해 예제를 업데이트 할 것입니다.
16:54에 서른 두 대령

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를 사용하면 평생 동안 직렬화를 해제하고 그 후 입력 데이터에서 차용하려고합니다. 컴파일러의 제한 사항 인 솔루션의 일부는 serde :: DeserializeOwned 이며 serde impl은 deserializer에서 데이터를 빌릴 수 없습니다.
attdona

해야 이 해결 방법은 당신을 위해 작동? Vec<u8>어딘가에 할당해야합니다 : 할당을 아래로 이동합니다 deserialize.
attdona

예 글쎄, 난 할 수 그냥 포기하고 수명을 제거 할 수 있지만 그때 제로 복사 직렬화를 가질 수 없습니다 그것은 질문의 요점을 패배.
대령

0

문제는 처리기 가 HK 제약 조건으로 가능한 모든 수명 을 처리 할 수 ​​있도록 요청 하는 것입니다. 컴파일러에서 확인할 수없는 동등성을 만들 수는 없습니다 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 ). 모르는 경우 출력은 함수를 매개 변수화하는 수명에 따라 달라질 수 있습니다 . 유니버스의 모든 수명에 대해 (평생에 따라 다름) 유형을 반환하도록 해당 함수를 요청 하면 컴파일러가 혼동 될 수 있습니다. '지역을 위반하지 않고이 제약 조건을 확인할 수 없으며 제약 조건이 실제로 수명에 종속 되지 않음을 알 수 없습니다 . 'aVec<u8>'a
val

내 대답의 newtype 래퍼가 관련 유형을 사용하는 동안 제대로 작동한다고 생각하면 그렇지 않습니다. 나는 당신이 다른 생애 동안 다른 연관된 유형을 가질 수 있다고 생각하지 않습니다. 임펄스를 배치해야하는 글로벌 범위에서 사용할 수있는 유일한 명명 된 수명은 'static어떻게 다른 수명 동안 물건을 구현할 것인가?
대령
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.