【问题标题】:Compile time initialization of an associative array关联数组的编译时初始化
【发布时间】:2019-01-28 08:24:19
【问题描述】:

根据 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 年,这在实践中会变成一个特性吗?

事实上,这只是我实际问题的前奏:

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

在下面的示例中,我可以使用在编译时运行的生成器函数(使用 CTFE)初始化模块级别 string[] doubleUnits,正如 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);
}

【问题讨论】:

    标签: d


    【解决方案1】:

    由于编译器不知道运行时格式,因此无法在编译时执行 内置 AA。它知道运行时接口,也知道编译时内存布局......但是运行时内存布局被委托给库,所以编译器不知道如何形成它。因此出现错误。

    但是,如果你要实现自己的 AA 类型实现,那么你可以编写 CTFE 代码来布局它,然后编译器可以在编译时进行。

    许多年前,这是作为修复方案提出的 - 用恰好适合编译器接口的库 AA 替换内置的魔术实现。然后它可以做到这一切。问题是库类型无法表达内置关联数组的所有魔力。我不记得确切的问题,但我认为这是关于 const 和其他属性交互的问题。

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

    当然,实现自己的 AA 可能需要一些代码,而且可能不值得,但如果 CT 初始化是必须的,这是让它工作的方法。

    (我个人觉得静态构造函数已经足够好了...)

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-06
        • 2016-03-22
        • 1970-01-01
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多