炫耀D的超能力

作者:伊森.沃森(Ethan Watson)
为什么用d?

序号特点
1节约成本
2易于从C++/C#中学习
3很容易写干净代码
4内省鼓励可维护性
5但未广泛使用

解析模板参数

常见代码问题:

void SomeFunc( bool ImportantParam, bool AnotherImportantParam );
SomeFunc( false, true );

常见方法:

enum ImportantParam          { Off, On }
enum AnotherImportantParam   { Off, On }
void SomeFunc( ImportantParam p1, AnotherImportantParam p2 );
SomeFunc( ImportantParam.Off, AnotherImportantParam.On );

D有库方案:

import std.typecons;
alias ImportantParam = Flag!"ImportantParam";
alias AnotherImportantParam = Flag!"AnotherImportantParam";
SomeFunc( ImportantParam.no, AnotherImportantParam.yes );

但模板呢?

struct SomeStruct( ImportantParam p1, AnotherImportantParam p2 )
{
   static if( p1 == ImportantParam.yes )
   {
       int SomeImportantInt;
   }
   static if( p2 == AnotherImportantParam.yes )
   {
       float SomeImportantFloat;
   }
}
//1
struct SomeStruct( ImportantParam p1 = ImportantParam.no,
           AnotherImportantParam p2 = AnotherImportantParam.no )
{
   static if( p1 == ImportantParam.yes )
   {
       int SomeImportantInt;
   }
   static if( p2 == AnotherImportantParam.yes )
   {
       float SomeImportantFloat;
   }
}

解析模板参数:

struct SomeStruct( ParameterList... )
{
}
alias DodgyStruct = SomeStruct!( SomeType );
alias DodgyStruct2 = SomeStruct!( 42.0f );
alias DodgyStruct3 = SomeStruct!( SomeFunc );
alias ReallyDodgyStruct = SomeStruct!( int, 42.0f, SomeFunc );

这儿:

struct SomeStruct( DefaultOverrides... )
   if( DefaultOverrides.length >= 0 )
{
   // 这里解析参数
   // 但如何?
   static foreach( Override; DefaultOverrides )
   {
       // 很干净
   }
}

接着:

import std.typecons;
alias ImportantParam = Flag!"ImportantParam";
alias AnotherImportantParam = Flag!"AnotherImportantParam";
alias DodgyStruct = SomeStruct!( ImportantParam.no,AnotherImportantParam.yes );

用枚举串:

enum Params : string
{
   Important = "加整至构",
   AnotherImportant = "加浮至构",
}
// alias DodgyStruct = SomeStruct!( ImportantParam.yes,AnotherImportantParam.no );
alias DodgyStruct = SomeStruct!( Params.AnotherImportantParam );
//接着
enum Params : string
{
   Important = "加整至构",
   AnotherImportant = "加浮至构",
}
bool[ Params ] ParamSet;//这里

提示,从枚造元组:

enum Params : string
{
   Important = "加整至构",
   AnotherImportant = "加浮至构",
}
alias AllParams = __traits( allMembers, Params );
pragma( msg, AllParams.stringof );
// tuple("Important", "AnotherImportant")

接着:

bool[ Params.length ] SetParams;
//参数集
foreach( ParamIndex, ParamName; AllParams )
{
   // 插件
   mixin( "enum ThisParam = Params." ~ ParamName ~ ";" );
   if( DefaultOverrides.contains( ThisParam ) )//重载是否有该参
   {
       SetParams[ ParamIndex ] = true;
   }
}

但!有个小问题:

alias DodgyStruct = SomeStruct!( Params.ImportantParam,Params.AnotherImportantParam );
// 生成相同代码,但完成不同类型
alias DodgyStruct = SomeStruct!( Params.AnotherImportantParam,Params.ImportantParam );

减少模板冗余

struct BitfieldFrom( T ) if( is( T == enum ) )
{
   alias Members = __traits( allMembers, T );
   static foreach( Index, Val; Members )
   {
       mixin( "@property bool " ~ Val ~ "() const"
       ~ "{ return IsSet[" ~ Index.stringof ~ "]; }" );
   }
   bool[ Members.length ] IsSet; // 可深入
   this( T[] SetThese... );
}

接着:

alias ThisBitfield = BitfieldFrom!Params;
// 转为Params[]
ThisBitfield someBits       = ThisBitfield( Params.Important, Params.AnotherImportant, Params.ReallyImportant );
ThisBitfield someOtherBits  = ThisBitfield( Params.SomethingImportant );

来到:

struct SomeDodgyStruct( BitfieldFrom!Params TheseParams )
{
   static if( TheseParams.ImportantParam )
   {
       int SomeImportantInt;
   }
   static if( TheseParams.AnotherImportantParam )
   {
       float SomeImportantFloat;
   }
}

外部自省生成代码

先造消息:

module some.module;
struct ImportantMessage
{
   int      param;
}

自动收集消息:

Automated Message Gathering
// 如前
alias Members = __traits( allMembers, Params );
// 从整个模块取
alias ModuleMembers = __traits( allMembers, Module!"some.module" );
pragma( msg, ModuleMembers.stringof );
// tuple("ImportantMessage")

问题来了:

module some.module;
struct ImportantMessage
{
   int      param;
}
// 忽略该构,其他地方用,它不是消息
struct SomeImportantStruct
{
   string   arcaneknowledge;
}

用定属

// 编译时可查询,提取和操作的属性,只需要加@
@SomeType  struct SomeStruct {}
@( 42.0f ) struct SomeStruct {}
@SomeFunc  struct SomeStruct {}

消息类型用定属:

struct ServerMessage { }
struct ClientMessage { }

给消息加上标签:

@ServerMessage
struct ImportantMessage { bool bParam; }
@ClientMessage
struct AnotherImportantMessage { bool bParam; }
@ServerMessage @ClientMessage
struct Ping { }
@ServerMessage @ClientMessage
struct Pong { }

提示,指示用定属:

struct UDA { }
@UDA struct ClientMessage { }
@UDA struct ServerMessage { }

检查消息类型:

alias AllAttributes = __traits( getAttributes, MessageType );
//1
import std.traits : hasUDA;
enum PingIsClient = hasUDA!( Ping, ClientMessage );
enum IsClientMessage( T ) = hasUDA!( T, ClientMessage );
enum IsServerMessage( T ) = hasUDA!( T, ServerMessage );

一行取所有消息:

import std.meta : Filter;
alias ClientMessages = Filter!( IsClientMessage, ModuleMembers );
alias ServerMessages = Filter!( IsServerMessage, ModuleMembers );

提示,通过哈希取唯一标识

ulong MakeHash( string val );
enum UniqueID( T ) = T.stringof.MakeHash; 
// 不要这样
enum UniqueID( T ) = fullyQualifiedName!( T ).MakeHash;
enum SomeStructID = UniqueID!SomeStruct; // HashOf( "some.module.SomeStruct" )

生成:

MessageCheck: switch( bytestream.ConsumeMessageID )
{
   static foreach( Message; FromClientMessages )
   {
       case UniqueID!Message:
           onReceived( bytestream.Deserialise!Message );
           break MessageCheck;
   }
   default:
       assert( false, "无效消息" );
       break;
}

外部:

final void onReceive( ref const( Ping ) msg )
{
   Pong pong;
   sendMessage( pong );
}
final void onReceive( ref const( Pong ) msg )
{
   writeln( "Pong!" );
}

重复行为:

final void onReceive( ref const( Ping ) msg );
final void onReceive( ref const( Pong ) msg );

继续:

class ClientServerCommon
{
   final void onReceive( ref const( Ping ) msg );
   final void onReceive( ref const( Pong ) msg );
}//这样不好
class ClientCommon : ClientServerCommon { }
class EditorClient : ClientCommon { }
class DebugClient : ClientCommon { }
//变成下面
interface ClientServerCommon
{
   final void onReceive( ref const( Ping ) msg );
   final void onReceive( ref const( Pong ) msg );
}//不好
class ClientCommon : ClientServerCommon, ClientCommon { }
class EditorClient : ClientServerCommon, ClientCommon { }
class DebugClient : ClientServerCommon, ClientCommon { }

重复行为:

mixin template PingPong()
{
   final void onReceive( ref Pong msg );
   final void onReceive( ref Ping msg );
   int SomeTrackingVal;
}
class Client
{
   mixin PingPong!();
}

行为规则:每模块一个,模块名必须为行为名小写.

module behaviors;
@UDA struct Behavior { }
mixin template Behaviors( Names... )
{
   static foreach( Name; Names )
   {
       mixin( "import behaviors." ~ Name.toLower ~ " : " ~ Name ~ ";" );
       mixin( "mixin behaviors." ~ Name.toLower ~ "." ~ Name ~ "!();" );
   }
}

乒乓行为:

module behaviors.pingpong;
@Behavior
mixin template PingPong()
{
   final void onReceive( ref Pong msg );
   final void onReceive( ref Ping msg );
}

行为

class Server
{
   // 行为在该点是部分类
   mixin Behaviors!( "PingPong",
                     "HandShake",
                     "Terminate" );
}
class EditorClient
{
   mixin Behaviors!( "PingPong" );
}

特殊行为:

final void onReceive( ref Pong msg )
{
   static if( IsServer )
   {
       // 干活
   }
   else static if( IsClient )
   {
       // 干其他活
   }
}
//
module behaviors.pingpong;
@Behavior
mixin template PingPong( Mode ThisMode )
{
   final void onReceive( ref Pong msg );
   final void onReceive( ref Ping msg );
}//特化乒乓

特化行为:

class Client
{
   // 错误,该行为插件试实例化插件
   mixin Behaviors!( "PingPong!( Mode.Client )", "HandShake", "Terminate" );
}

同名模板

template SomeTemplate( T )
{
   enum SomeTemplate = T.init;
}
T val = SomeTemplate!T;
//
template SomeTemplate( T )
{
   T SomeTemplate( string SaySomething )
   {
       writeln( SaySomething );
       return T.init;
   }
}
T val = SomeTemplate!T( "赶快,好东西" );

减少模板冗余:

struct SomeDodgyStruct( BitfieldFrom!Params TheseParams )
{
   static if( TheseParams.ImportantParam )
   {
       int SomeImportantInt;
   }
   static if( TheseParams.AnotherImportantParam )
   {
       float SomeImportantFloat;
   }
}

类似:

enum IsParam( alias P ) = is( typeof( P ) == Params );
template SomeDodgyStruct( TheseParams... ) if( TheseParams.length >= 1 )
{
   alias ActualParams = Filter!( IsParam, TheseParams );//实际参数
   alias ParamBits = BitfieldFrom!Params;
//参数化
   alias SomeDodyStruct = SomeDodgyStruct!( ParamBits( [ ActualParams ] ) );//构建
}

接着:

alias DodgyStruct = SomeStruct!( Params.ImportantParam, Params.AnotherImportantParam );
// 感谢同名模板,生成相同代码
alias DodgyStruct = SomeStruct!( Params.AnotherImportantParam, Params.ImportantParam );

同名插件模板

template PingPong( T )
{
   @Behavior
   mixin template PingPong()
   {
       //手动实例化为PingPong!(Mode.Client)!();
   }
}

接着:

template PingPong( T )
{
   @Behavior
   mixin template PingPong()
   {
       // 错误,未定义T符号.插件不知道周围模板
       T SomeValue;
   }
}

串插件

int SomeVal;
//下面生成:
mixin( "int SomeVal;" );
//同样生成:
enum PartOne = "int ";
enum PartTwo = "SomeVal;";
mixin( PartOne ~ PartTwo );
//同样:
string MakeSomeVal( T )()
{
   return T.stringof ~ " SomeVal;";
}
mixin( MakeSomeVal!int );

串插件/模板插件都要求是合法代码.与相比,这才是维护大量代码的正确方法.

同名插件模板:

// 要像`PingPong!( Mode.Client )`实例化
template EponymousMixin( Params... )
{
   // 新插件是另一插件的包装
    mixin template EponymousMixin( )
    {
        mixin ActualMixinTemplate!( Params );
    }
}

核心,生成插件:

string GenerateMixin( string DesiredName, string MixinName )
{
   return = "template " ~ DesiredName ~ "( Params... )"
   ~ "{"
   ~ "  enum MixinString = \"mixin template " ~ DesiredName ~ "()"
   ~ "  {"
   ~ "    mixin " ~ MixinName ~ "!( AliasSeq!( \" ~ ToString!Params ~ \" ) );"
   ~ "  };"
   ~ "  mixin( MixinString );"
   ~ "}";
}

有了它:

module behaviors.pingpong;
@Behavior
mixin template PingPongImpl( Mode ThisMode )
{
  final void onReceive( ref Pong msg );
  final void onReceive( ref Ping msg );
}
mixin( GenerateMixin( "PingPong", "PingPongImpl" ) );//生成

看看:

class Client
{
   // 工作很好,可读可维护,最小维护量
   mixin Behaviors!( "PingPong!( Mode.Client )", "HandShake", "Terminate" );
}

同样:

@Behavior
mixin template SendReceive( alias CanSendCheck, ReceiveMessages... );
class Client
{
   mixin Behaviors!( "SendReceive!( CanClientSend, FromServerMessages )" );
}
class Server
{
   mixin Behaviors!( "SendReceive!( CanServerSend, FromClientMessages )" );
}

模板化用定属

早先:

MessageCheck: switch( MessageID )
{
   static foreach( Message; ClientMessages )
   {
       case UniqueID!Message:
           onReceived( bytestream.Deserialise!Message );//这里
           Break MessageCheck;
   }
   default:
       assert( false, "无效消息!" );
       break;
}

序化对象

auto Deserialise( T )( ref byte[] bytestream )
{
   // 如何?
}

这样:

auto Deserialise( T )( ref byte[] bytestream ) if( is( T == struct ) )
{
   T output;
   static foreach( Index, Member; T.tupleof )
   {
       output.tupleof[ Index ] = bytestream.Deserialise!( typeof( Member ) );
   }
   return output;
}

未序化:

@UDA struct NoSerialise { }
struct SomeStruct
{
   int SerialiseThis;
   @NoSerialise float IgnoreThis = 42.0f;
   double AlsoSerialiseThis = 0.0f;
}

解序化:

auto Deserialise( T )( ref byte[] bytestream ) if( is( T == struct ) )
{
   T output;
   static foreach( Index, Member; T.tupleof )
   {
       static if( !hasUDA!( Member, NoSerialise ) )
       {
           output.tupleof[ Index ] = bytestream.Deserialise!( typeof( Member ) );
       }
   }
   return output;
}

再访问用定属:

@SomeType  struct SomeStruct {}
@( 42.0f ) struct SomeStruct {}
@SomeFunc  struct SomeStruct{}
struct SomeTemplate( T )
{
   T SomeValue;
}
@SomeTemplate!int struct SomeStruct {}

用模板化用定属序化勾挂

@UDA struct OnSerialise( alias Func )         { alias Call = Func; }
@UDA struct OnDeserialise( alias Func )       { alias Call = Func; }
@UDA struct OnPreSerialise( alias Func )      { alias Call = Func; }
@UDA struct OnPreDeserialise( alias Func )    { alias Call = Func; }
@UDA struct OnPostSerialise( alias Func )     { alias Call = Func; }
@UDA struct OnPostDeserialise( alias Func )   { alias Call = Func; }

距离:

struct Distance
{
   @OnSerialise!( x => x.sqrt )
   @OnDeserialise!( x => x * x )
   double value = 0.0;
   alias value this;
}

接着:

static foreach( Index, Member; T.tupleof )
{
   static if( hasUDA!( Member, OnDeserialise ) )
   {
       output.tupleof[ Index ] = getUDAs!( Member, OnDeserialise )[ 0 ]
                          .Call( bytestream.Deserialise!( typeof( Member ) ) );
   }
   else
   {
      output.tupleof[ Index ] = bytestream.Deserialise!( typeof( Member ) );
   }
}

距离同上.

回家研究

位字段类型和限定大小.

@UDA struct Storage( T, ulong BitCount );
enum Params : string
{
   @Storage!( int, 4 )
   Important = "加整至构",
   @Storage!( uint, 2 )
   AnotherImportant = "加浮至构",
}

用定属,命令行解析器

@DefaultArgParser( "file", "Input files", ArgIs.Repeating )
bool ParseInputFileParam( string value, int priorcallcount, ref ProgramParams
params );
@ArgParser( "o", "output", "Target file", 1.MinCalls, 1.MaxCalls )
bool ParseInputFileParam( string value, int priorcallcount, ref ProgramParams
params );
@ArgParser( "i", "iwad", "IWAD,输入文件之基",
1.MaxCalls )
bool ParseIWADParam( string value, int priorcallcount, ref ProgramParams
params );

统调,但模板:

struct Symbols( S... )
{
   alias S this;
   template opDispatch( string symbol );
 // 神奇
}
alias TheseSymbols = Symbols!( int, float, string, bool );
pragma( msg, Symbols[ 1 ].stringof );
// 当前不行!
alias UTESFilterAlias = TheseSymbols.Filter!( IsFloat );
posted @   zjh6  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示