Инициализация времени компиляции ассоциативного массива - PullRequest
0 голосов
/ 28 января 2019

Согласно D Language Reference статическая инициализация ассоциативных массивов ассоциативный массив (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]

Небольшое прибегание к поиску указывает, что это давняя ошибка (?) в языке:

Так что я знаю, как обойти это с помощью статического конструктора .Однако, учитывая, что проблема существует уже около 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 голосов
/ 10 апреля 2019

Невозможно выполнить встроенные AA, инициализированные во время компиляции, потому что компилятор не знает о формате времени выполнения.Он знает интерфейс времени выполнения и знает макет памяти времени компиляции ... но макет памяти времени выполнения делегирован библиотеке, поэтому компилятор не знает, как его сформировать.Отсюда ошибка.

Но, если бы вы реализовали свою собственную реализацию типа AA, то вы можете написать код CTFE, чтобы выложить его, а затем компилятор мог бы сделать это во время компиляции.

Много лет назад это было предложено в качестве исправления - замените встроенную магическую реализацию библиотекой AA, которая соответствует интерфейсу компилятора.Тогда это может сделать все это.Проблема заключалась в том, что типы библиотек не могут выразить всю магию, которую делают встроенные ассоциативные массивы.Я не помню точных проблем, но я думаю, что речь шла о взаимодействии const и других атрибутов.

Но, тем не менее, даже если это не удалось для 100% замены, ваша собственная реализация замены на 90% можетну будь достаточно хорош для тебя.Объявления будут выглядеть по-разному - MyAA!(string, int) вместо string[int], и литералы для него различны (хотя, возможно, makeMyAA(["foo" : 10]); вспомогательная функция ctfe, которая берет встроенный литерал и преобразует его в ваш формат), ноиспользование будет в основном таким же благодаря перегрузке операторов.

Конечно, реализация вашего собственного AA может быть немного кода и, возможно, не стоит, но это способ заставить его работать, если инициализация CT являетсядолжен иметь.

(лично я нахожу статический конструктор достаточно хорошим ...)

0 голосов
/ 09 апреля 2019

В настоящее время это невозможно (как описано в документе с описанием языка).Я отправил изменение в спецификации, отметив, что эта функция еще не реализована.Это определенно запланировано, но еще не реализовано ...

...