使用泛型

时间:2016-06-10 22:39:17

标签: rust

我开始使用Rust来创建一个新库。我试图围绕可能的方式来实现以下内容。

以下是更多期望的表达,而不是真正的语法。当我去实现其中一个别名特征时,我尝试表达的所有方法都不会编译或编译。

struct ConcreteType;
struct CommonType;

trait Handler<Rin, Rout = Rin>{
    fn handle_event(&self, msg: &Rin);
}

// alias Handler with one of the types defined as a common case
trait HandlerToMessage<M> : Handler <ConcreteType, M>{
    fn handle_event(&self, msg: &ConcreteType) {
        // default implementation of parent trait
        // example is simplified, forget about how Rout/M is actually used
        self.decode(msg)
    }

    // method to implement
    fn decode(&self, msg: &ConcreteType) -> M;
}

// another alias for most common case where Rin/Rout are ConcreteType, CommonType most often
trait HandlerToCommonType : HandlerToMessage <ConcreteType, CommonType>{
    fn decode(&self, msg: &ConcreteType) -> CommonType 
    {
       ...
    };
}

使用关联类型的替代方案

trait Handler{
    type Rin;
    type Rout;    // not yet able to do Rout = Rin with associated types

    fn handle_event(&self, msg: &Self::Rin) -> Self::Rout;
}


trait HandlerToMessage : Handler <Rin=ConcreteType>{
    fn handle_event(&self, msg: &Self::Rin) {
        // common functionality
        self.decode(msg)
    }

    // method to implement
    fn decode(&self, msg: &Self::Rin) -> Self::Rout;
}

trait HandlerToCommonType : HandlerToMessage <Rout=CommonType>{

    fn decode(&self, msg: &ConcreteType) -> CommonType
    {
        ...
    } 
}

在C ++中,这大致是我想要完成的事情

// real world example I've seen in the wild of this structure
template <class Rout>
class Context {
public:
    void dispatch(Rout* msg);
};

template <class Rin, Rout = Rin>
class ReadHandler {
public:
    void read (Context* ctx, Rin* msg) = 0;

private:
    Context<Rout> ctx_;
};

// very common to convert from a byte buffer some message type
template <class M>
class BytesToMessageDecoder : ReadHandler<IOBuffer, M> {
public:
    // Template method pattern
    void read (Context* ctx, IOBuffer* msg) {
        M msgOut;
        bool success;
        success = this->decode(msg, &msgOut);
        if (success) {
            ctx->dispatch(msgOut);
        }                
    }

    bool decode(IOBuffer* msg, M* msgOut) = 0;

}

// convert one byte buffer to another is common
typedef BytesToMessageDecoder<IOBuffer> BytesToBytesDecoder;


// Concrete implementations
// look for fixed number of bytes incoming
class FixedLengthFrameDecoder : BytesToBytesDecoder {
    bool decode(IOBuffer* msg, IOBuffer* msgOut) { ... }
}

// fields are prefixed with a length. Wait for that many bytes and then dispatch
class LengthBasedFieldDecoder: BytesToBytesDecoder {
    bool decode(IOBuffer* msg, IOBuffer* msgOut) { ... }
}

class StringDecoder : BytesToMessageDecoder<std::string> { 
    // decode from byte buffer to a string
    bool decode(IOBuffer* msg, std::string* msgOut) { ... }
}

基本上,顶级特征Handler是最通用的,但可能不是由高级图书馆用户以外的任何人实现的。 HandlerToMessage特征是一种常见的转化,我们将ConcreteType转换为其他类型。该库可以实现其中的几个。 HandlerToCommonType是许多库类型想要开始的最常见情况。

Rout特征中Handler的使用方式的详细信息并不重要。我试图简化这个例子并留下一些争论,希望能让我想要传达更简洁的内容。我对此的所有搜索都让我觉得这不可能传达或者我在滥用它。我不太明白,如果这属于新的专业化实施,但我不能从我的理解中感受到它。

我意识到Rust不是C ++,所以我尝试做的事情可能不受支持或者语法不同。无论是正确的语法还是更惯用的Rust方式,都可以获得任何帮助。

1 个答案:

答案 0 :(得分:0)

也许你可以拥有单独的特征,并为另一个的所有实施者实施一个:

struct ConcreteType;
struct CommonType;

trait Handler<Input, Output = Input> {
    fn handle_event(&self, msg: &Input) -> Output;
}

trait HandlerToMessage<M> {
    fn decode(&self, msg: &ConcreteType) -> M;
}

impl<T, M> Handler<ConcreteType, M> for T
    where T: HandlerToMessage<M>
{
    fn handle_event(&self, msg: &ConcreteType) -> M {
        self.decode(msg)
    }
}

impl HandlerToMessage<CommonType> for () {
    fn decode(&self, _msg: &ConcreteType) -> CommonType {
        unimplemented!()
    }
}

fn main() {}

最后一个真的很尴尬,因为你通常会为一个具体的类型实现一个特性,但你还没有真正提出任何有意义的实现。