首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >关联数组的编译时初始化

关联数组的编译时初始化
EN

Stack Overflow用户
提问于 2019-01-28 16:24:19
回答 2查看 255关注 0票数 2

根据D语言参考static initialization of associative arrays,关联数组(AA)可以这样初始化:

代码语言:javascript
复制
immutable long[string] aa = [
  "foo": 5,
  "bar": 10,
  "baz": 2000
];

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

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

代码语言:javascript
复制
$ 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]

用谷歌搜索一下似乎表明这是一个长期存在的bug (?)在语言中:

所以我知道如何使用static constructor来解决这个问题。然而,考虑到这个问题已经存在了大约10年,这在实践中会变成一个特性吗?

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

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

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

代码语言:javascript
复制
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);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-10 22:41:11

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

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

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

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

当然,实现你自己的AA可能是一段代码,可能不值得这样做,但如果CT初始化是必须的,这是让它工作的方法。

(就我个人而言,我发现静态构造函数已经足够好了……)

票数 3
EN

Stack Overflow用户

发布于 2019-04-10 04:01:17

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54397968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档