编译时间评估

fwe*_*end 12 d compile-time

如果我写

enum chars = digits ~ uppercase;
Run Code Online (Sandbox Code Playgroud)

字符串是否会在编译时连接?我假设它会.如果我用字符串文字或CTFE函数替换它,我无法测量任何显着的性能差异(甚至称它为一亿次).如果我用const替换enum,我确实会有所不同.我被告知这样编写效率很低.我觉得这很方便,我看不出效率低下.(顺便说一句,该行是一个递归调用的函数).

完整代码(转换为具有不同基数的数字系统)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}
Run Code Online (Sandbox Code Playgroud)

编辑:更新的代码,以回应评论,与问题无关

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}
Run Code Online (Sandbox Code Playgroud)

rat*_*eak 9

enum这样的实例化总是在编译时进行评估(并且在编译时无法进行评估时抛出编译错误)

因此,连接在编译时完成,并且不可变版本存储在代码中并在运行时引用


gmf*_*ett 5

检查字符串是否在编译时连接的一种方法是编译代码并检查目标文件.假设您的文件被调用test.d:

dmd -c test.d
objdump test.o | grep -C3 "012345"
Run Code Online (Sandbox Code Playgroud)

......应该产生类似的东西:

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......
Run Code Online (Sandbox Code Playgroud)

(这是在Linux上;在其他平台上,您需要使用不同的工具来检查目标文件.)

如果你更改enumconststring,你将(可能)没有输出:没有连接字符串可供grep查找.

但是编译器可能会在编译时连接字符串,即使enum不使用它也是如此.考虑这个程序:

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }
Run Code Online (Sandbox Code Playgroud)

现在,编译它,并检查目标文件:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........
Run Code Online (Sandbox Code Playgroud)

我们看到了x,y并且z都是静态文字.(马克a,bc作为const代替enum,你可能会看到不同的行为.)所以,虽然enum是编译时计算的担保,不存在enum不能防止编译时的评价.