我开始使用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方式,都可以获得任何帮助。
答案 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() {}
最后一个真的很尴尬,因为你通常会为一个具体的类型实现一个特性,但你还没有真正提出任何有意义的实现。