Есть ли способ использовать <const> внутри таблицы Lua?

Начиная с Lua 5.4, синтаксис <const> позволяет нам устанавливать константные переменные. Я заметил, что это не влияет транзитивно на поля внутри таблицы.

local x <const> = {
    a = {1,2,3},
    b = {5,6,7}
}

x = 5 -- error
x.a = 9 -- no error

Таблица x является константной и не может быть переназначена, но поля внутри таблицы могут.

Есть ли способ сделать поля внутри таблицы константными только с помощью синтаксиса? Я знаю, что это возможно с помощью метаметодов index и newindex, но мне интересно, возможно ли это с помощью простого синтаксиса, такого как <const>.

Я попробовал следующее, но выдает синтаксическую ошибку:


local x <const> = {
    a <const> = {1,2,3},
    b <const> = {5,6,7}
}

4
87
2

Ответы:

Решено

const используется для объявления константы локальной переменной, но таблицы не являются переменными: они являются объектами (или значениями на языке Lua). В Lua нет неизменяемых таблиц. В коде OP x — это постоянная переменная, инициализированная для хранения таблицы в качестве своего значения; дальнейшие назначения x выполнить невозможно. Значение, которое содержит x, является таблицей, и этот объект является изменяемым.

В Lua невозможно использовать const так, как описано в вопросе ОП. В опубликованном коде x — это (постоянная) переменная, к которой привязана таблица. В этой таблице a и b не переменные, а ключи. В Lua ключ (или индекс ассоциативного массива) — это другое значение. Но помните: значения не являются переменными, скорее, переменные хранят значения. Возможно, будет полезно вспомнить, что x.a — это всего лишь синтаксический сахар для x["a"], т. е. в таблице x есть слот, индексированный по значению "a". Lua позволяет ассоциировать атрибут const с переменными, но не со значениями, поэтому a и b нельзя создавать const.

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


Вот немного другая точка зрения. (Ответ по-прежнему нет.)

Частично причина того, что <const> работает так, заключается в том, что (по крайней мере, в стандартной реализации Lua) он вычисляется исключительно во время компиляции. Это очень просто сделать — локальные переменные имеют лексическую область видимости, и компилятор должен знать об объявлении переменной, чтобы что-либо сделать — например, ему нужно знать, что она на самом деле является локальной, и является ли она локальной. повышение стоимости.

Среда выполнения виртуальной машины ничего не знает о <const>. Единственная разница заключается в том, что компилятор решил использовать эту информацию для некоторой оптимизации.

Эта парадигма не очень хорошо работает для теоретической функции константной таблицы. Мы можем спросить, разумно ли ожидать, что компилятор сможет определить, является ли таблица константной (и если да, то какие поля или что-то еще, в зависимости от того, как вы реализуете эту функцию). Во многих случаях это может быть возможно с помощью сложного статического анализа, но такой анализ, вероятно, намного сложнее, чем все, что сейчас делает компилятор Lua, и вы можете начать сталкиваться с проблемами типа проблемы остановки в более сложных крайних случаях.

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

Если вы не делаете этого во время компиляции, я думаю, вы делаете это во время выполнения. Это означает, что у вас будет некоторый тег или метаданные, хранящиеся в памяти вместе с табличным объектом, и виртуальная машина проверит это во время выполнения. Как вы знаете, Lua имеет гибкую, доступную пользователю систему, которая допускает такую ​​​​возможность — метатаблицы. Да, это правда, что предложенный вами синтаксис может быть очень удобен для вашего конкретного случая использования, но, возможно, нецелесообразно использовать один и тот же синтаксис для двух функций, которые на самом деле работают совершенно по-разному друг от друга. (Представьте себе вопрос: «Почему <const> произошел сбой во время компиляции/загрузки здесь, а там произошел сбой во время выполнения?») И я думаю, что творческое использование существующих функций и определение соответствующих вспомогательных функций могут позволить достичь некоторого компромисса между удобством синтаксиса , стоимость выполнения и читаемость.