关联数组的编译时初始化

时间:2019-01-28 08:24:19

标签: d

根据D语言参考static initialization of associative arrays,可以通过以下方式初始化关联数组(AA):

immutable long[string] aa = [
  "foo": 5,
  "bar": 10,
  "baz": 2000
];

void main()
{
  import std.stdio : writefln;
  writefln("(aa = %s)", aa);
}

但是该示例未使用合理的最新DMD进行编译:

$ dmd --version
DMD64 D Compiler v2.083.0
Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright
$ dmd -de -w so_003.d
so_003.d(3): Error: non-constant expression ["foo":5L, "bar":10L, "baz":2000L]

有点谷歌搜索似乎表明这是该语言的一个长期存在的错误(?):

因此,我知道如何使用static constructor解决该问题。但是考虑到这个问题已经存在大约10年了,这在实践中是否变成了一个特征?

实际上,这只是我的实际问题的序幕:

是否可以在编译时初始化关联数组?

在下面的示例中,我可以使用生成器函数来初始化模块级别string[] doubleUnits,该生成器函数在编译时(使用CTFE)运行,由pragma(msg)证明。而且我可以在运行时初始化int[string] doubleUnitMap。但是如何在编译时初始化AA?

import std.stdio : writefln;

immutable char[] units = ['a', 'b', 'c'];

immutable string[] doubleUnits = generateDoubleUnits(units);
pragma(msg, "compile time: ", doubleUnits);

string[] generateDoubleUnits(immutable char[] units)
pure
{
  import std.format : format;

  string[] buffer;
  foreach(unit; units) {
    buffer ~= format("%s%s", unit, unit);
  }

  return buffer;
}

immutable int[string] doubleUnitMap;
// pragma(msg) below triggers the following compilation error:
// Error: static variable doubleUnitMap cannot be read at compile time
//        while evaluating pragma(msg, "compile time: ", doubleUnitMap)
// pragma(msg, "compile time: ", doubleUnitMap);

shared static this() {
  doubleUnitMap = generateDoubleUnitMap(units);
}

int[string] generateDoubleUnitMap(immutable char[] units)
pure
{
  import std.format : format;

  int[string] buffer;
  foreach(unit; units) {
    string key = format("%s%s", unit, unit);
    buffer[key] = 1;
  }

  return buffer;
}

void main()
{
  writefln("(doubleUnits = %s)", doubleUnits);
  writefln("(doubleUnitMap = %s)", doubleUnitMap);
}

2 个答案:

答案 0 :(得分:3)

不可能执行在编译时初始化的内置 AA,因为编译器不了解运行时格式。它知道运行时接口,也知道编译时内存布局...但是将运行时内存布局委托给了库,因此编译器不知道如何形成它。因此是错误。

但是,如果您要实现自己的AA类型实现,则可以编写CTFE代码以对其进行布局,然后编译器可以在编译时进行构建。

很多年前,它是作为修复程序提出的-用恰好适合编译器接口的库AA替换内置的magic实现。然后就可以完成所有操作。问题在于库类型不能表达内置关联数组所具有的所有魔力。我不记得确切的问题,但我认为这与const和其他属性交互有关。

但是,即使100%替换失败,您自己实施90%替换对您来说也足够好。声明看起来会有所不同-MyAA!(string, int)而不是string[int],并且其字面量也有所不同(尽管可能是makeMyAA(["foo" : 10]);一个辅助ctfe函数,它使用内置字面量并将其转换为您的格式),但由于运算符重载,用法基本相同。

当然,实现自己的AA可能需要一些代码,可能不值得,但是如果必须进行CT初始化,这是使其工作的一种方式。

(我个人认为静态构造函数足够好...)

答案 1 :(得分:1)

目前,这是不可能的(如语言规范文档中所述)。我已在规范中提交了更改,并注意到该功能尚未实现。肯定是有计划的,但尚未实施...