d标准库选讲
作者:阿里
思想:AA:通过组合特征,来完成功能.
 内容:涉及iota,parallel,static if,std.concurrency.receive和SumType.
iota
auto iota(B, E)(B begin, E end)
if (!isIntegral!(CommonType!(B, E)) &&
     !isFloatingPoint!(CommonType!(B, E)) &&
     !isPointer!(CommonType!(B, E)) &&
     is(typeof((ref B b) { ++b; })) &&
     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
{
    // ...
}
D语言:更简单,更安全,更正确,更快,节省时间.
 从dmd2.100.0开始,有54个标准模块.
//iota
auto iota(B, E, S)(B begin, E end, S step)
 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
           && isIntegral!S)
 {
      // ...
           void popFront()
           {
               assert(!empty);
               if (current == last) step = 0;
               else current += step;
           }
      // ...
 }
标准库用区间来抽象.
iota(0,10,2)//生成0,2,4,6,和8
简单iota示例:
struct MyNumbers {
    int begin;// 仅同整,可模板化
    int end;
    int step;
    bool empty() {
      return begin >= end;
    }
    int front() {
      return begin;
    }
    void popFront() {
      begin += step;// 对浮点,这不准确.
    }
 }
辅助函数:
MyNumbers myNumbers(int begin, int end, int step) {
    return MyNumbers(begin, end, step);
 }
//单元测试
unittest {
    assert(myNumbers(0, 10, 2).equal([0, 2, 4, 6, 8]));
 }
移动构至函数内,变成隐藏类型:
auto myNumbers(int begin, int end, int step) {
   struct MyNumbers {
      // 这次,无数字(成员),用参数.
      bool empty() {return begin >= end;}
      int front() {return begin;}
      void popFront() {begin += step;}
   }
    return MyNumbers();
 }
免责声明:这不必要地昂贵,因为是闭包,动态分配的上下文会始终保持活动状态.可这样:
auto myNumbers(int begin, int end, int step) {
    static struct MyNumbers {
      // ...
    }//静态构.
    return MyNumbers(begin, end, step);
 }
auto返回类型,表示自动推导返回类型.
auto iota(B, E, S)(B begin, E end, S step)
 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))&& isIntegral!S)
 { /* ... */ }
B,E,S表示类型.
 模板约束:B和E是整数或指针且S是整数时使用.
其余定义:
//无步.
auto iota(B, E)(B begin, E end)
 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
 {
      return iota(begin, end, CommonType!(B, E)(1));
 }
//无头参数
auto iota(E)(E end)
 if (is(typeof(iota(E(0), end))))
 {
      E begin = E(0);
      return iota(begin, end);
 }
//浮点版
auto iota(B, E, S)(B begin, E end, S step)
 if (isFloatingPoint!(CommonType!(B, E, S)))
 {
      // ...
           Value front() const { assert(!empty); return start + step * index; }
           void popFront()
           {
               assert(!empty);
               ++index;//start+=step对浮点没用.
           }
      // ...
 }
//无步浮点.
auto iota(B, E)(B begin, E end)
 if (isFloatingPoint!(CommonType!(B, E)))
 { /* ... */ }
用户定义的特化的一站式iota:
auto iota(B, E)(B begin, E end)
 if (!isIntegral!(CommonType!(B, E)) &&
      !isFloatingPoint!(CommonType!(B, E)) &&
      !isPointer!(CommonType!(B, E)) &&
      is(typeof((ref B b) { ++b; })) &&
      (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
 { /* ... */ }
CommonType为公共类型.即A,B都可转或三元运算符将选择的类型.如:
static assert(is (CommonType!(double, int, short) == double));
is(typeof(expr)),is和typeof都是编译时求值.
 typeof(expr):表达式的类型.
 is(Type):如果Type在语义上是正确的,则为true.示例:
//如下`is`式为假.
is(                     // 3) 假
     typeof(            // 2) λ没有类型
        (string s) {
          ++s;          // 1) 非法操作串.
        }
      )
等价于:
//`__traits`式为假.
__traits(compiles,(string s) { ++s; })
Unqual
去限定,这是头可变,
 推导模板类型时保留了限定符:
void main() {
    const a = 42;
    foo(a);
 }
 void foo(A)(A a) {
   A result;       // A推导为const(int),
   ++result;       // 因而,编译错误!
 }
//改为如下
void foo(A)(A a) {
   Unqual!A result;// 'result'是'int'
   ++result;       // 现在编译了.
}
并行
在所有cpu中并行处理元素.
Student[] students;
// ...
foreach (s; students.parallel) {
  // ...
}
//等价:
foreach (s; parallel(students)) {
  // ...
}
调度到全局区间对象成员函数的函数:
ParallelForeach!R parallel(R)(R range)
 {
      return taskPool.parallel(range);
 }
//带可选括号的等价物:
ParallelForeach!R parallel(R)(R range)
 {
      return taskPool().parallel(range);
 }
延迟初化的全局对象:
@property TaskPool taskPool() @trusted
 {
      import std.concurrency : initOnce;
      __gshared TaskPool pool;
      return initOnce!pool({
           auto p = new TaskPool(defaultPoolThreads);
           p.isDaemon = true;
           return p;
      }());
 }
initOnce用使用了互斥锁的initOnceLock.
 TaskPool.parallel返回ParallelForeach对象:
final class TaskPool
 {
 // ...
      ParallelForeach!R parallel(R)(R range)
      {
           // ...
      }
 }
ParallelForeach通过一对opApply函数支持foreach迭代:
private struct ParallelForeach(R)
 {
 // ...
      int opApply(scope NoIndexDg dg)
      {
           static if (randLen!R) {
               mixin(parallelApplyMixinRandomAccess);
           } else {
               mixin(parallelApplyMixinInputRange);
           }
      }
      int opApply(scope IndexDg dg) {  /* ... */ }
 }
实现,在串插件中:
private enum string parallelApplyMixinRandomAccess = q{
 // ...
      // 迭代是否有索引.
      enum withIndex = Parameters!(typeof(dg)).length == 2;
 // ...
      void doIt()
      {
        // ...
      }
      submitAndExecute(pool, &doIt);
      return 0;
 };
通过,UFCS/可选括号/互斥锁保护的延迟初化/opApply支持的每一/自省/串插件来实现.
内省设计的力量
auto r = iota(100)
         .map!(n => n * n)
         .stride(2) //也可用iota
         .take(5);
writeln(r);//[0, 4, 16, 36, 64]
writeln(r[2]);//这样呢?
//也可以.
因为,take/stride/map/iota都支持.
D拥有static if.
struct Take(Range)
 // ...
 {
      // ...
      static if (isRandomAccessRange!R)
      {
          // ...
          auto ref opIndex(size_t index)
          {
               assert(index < length,"越界"~ Take.stringof);
               return source[index];
          }
          // ...
      }
 }
匹配模式
D无此语言功能.但可模拟它.
 如,std.concurrency.receive可按消息类型分派不同闭包.
receive(
        (LinkTerminated msg) {
          // 终止消息
          // ...
        },
        (Result result) {
          // 发送结果,
          // ...
        },
        (Foo foo, Bar bar) {
          // 发送foo及bar
          // ...
        },
      );
std.concurrency用Variant发送各种类型消息:
struct Message
  {
      MsgType type;
      Variant data;
      // ...
  }
运行时线性搜索来匹配模式.ops为操作数组,Ops为类型元组.
foreach (i, t; Ops)
{
     alias Args = Parameters!(t);
     auto op = ops[i];
     // ...
     if (msg.convertsTo!(Args))// 用Variant.convertsTo
     {
         // 找到匹配
         // ... 调用'op'并返回 ...
     }
}
assert和static assert可提供有用的错误消息
 如,在std.concurrency.MessageBox.get内部:
class MessageBox
  {
      // ...
       bool get(T...)(scope T vals)
       {
           // ...
           static assert(T.length, "T不能为空");
           // ...
       }
      // ...
  }
更多:
static assert(a1.length != 1 || !is(a1[0] == Variant),"带参函数" ~ a1.stringof ~
"不能为连续函数");
Variant,类似C++的any,不推荐Algebraic.用SumType.
SumType
| 序号 | 特点 | 
|---|---|
| 1 | 匹配模式 | 
| 2 | 支持 自引用类型 | 
| 3 | 完整正确的推导属性,尽可能推导pure,@safe,@nogc和nothrow. | 
| 4 | 与 DIP1000(域)兼容的类型安全和内存安全API. | 
| 5 | 不依赖运行时 类型信息 | 
| 6 | 兼容 BetterC | 
示例:
//定义
struct Fahrenheit { double degrees; }
struct Celsius { double degrees; }
struct Kelvin { double degrees; }
alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin);
//构建
Temperature t1 = Fahrenheit(98.6);
Temperature t2 = Celsius(100);
Temperature t3 = Kelvin(273);
匹配模式:
Fahrenheit toFahrenheit(Temperature t) {
      return Fahrenheit(
          t.match!(
               (Fahrenheit f) => f.degrees,
               (Celsius c) => c.degrees * 9.0/5 + 32,
               (Kelvin k) => k.degrees * 9.0/5 - 459.4
           )
      );
 }
多重调度:
match!(// 4种处理器,处理3x3==9种情况
       (Fahrenheit f1, Fahrenheit f2) => writeln("Both F"),
       (Celsius c1, Celsius c2) => writeln("Both C"),
       (Kelvin k1, Kelvin k2) => writeln("Both K"),
       (_1, _2) => writeln("Different"),
  )(t1, t2);
编译时的SumType
构建查找处理器:
private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
// ...
enum matches = ()
{
   size_t[numCases] matches;
   // ...
   static foreach (caseId; 0 .. numCases)
   {
        static foreach (hid, handler; handlers)
        {
             static if (canMatch!(handler, valueTypes!caseId))
             {
                 // ...
                      matches[caseId] = hid;
                 // ...
             }
        }
   }
   return matches;
}();
构建处理程序名:
enum handlerName(size_t hid) = "handler" ~ toCtString!hid;
static foreach (size_t hid, handler; handlers)
{
   mixin("alias ", handlerName!hid, " = handler;");
}
编译时构建switch语句:
immutable argsId = TagTuple(args).toCaseId;
  final switch (argsId)
   {
       static foreach (caseId; 0 .. numCases)
       {
        case caseId:
             static if (matches[caseId] != noMatch)
             {
                  return mixin(handlerName!(matches[caseId]), "(", handlerArgs!caseId, ")");
             }
             else
             {
                  static if (exhaustive)
                  {
                      static assert(false,
                           "No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
                  }
                 else
                  {
                      throw new MatchException(
                           "No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
                  }
             }
   }
}
assert(false, "unreachable");
}
SumType支持递归数据类型.
alias Expr = SumType!(
   double,
   string,
   Tuple!(Op,"op",This*,"lhs",This*,"rhs")
);
// ...
struct This {}
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号