Программирование на Lua | ||
Часть I. Язык Глава 3. Выражения |
Конструкторы - это выражения, которые создают и инициализируют таблицы. Они являются отличительной особенностью Lua и одним из наиболее удобных и универсальных механизмов.
Простейшей формой конструктора является пустой конструктор,{}
, создающий пустую таблицу; мы уже встречали их ранее. Также, конструкторы могут инициализировать массивы (called also sequences or lists). Например, the statement
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}инициализирует
days[1]
строкой "Sunday"
(первый элемент всегда имеет индекс 1, а не 0), days[2]
строкой "Monday"
и т.д.:
print(days[4]) --> Wednesday
Конструкторы могут использовать не только константные выражения. При задании значений элементов можно использовать любые виды выражений. Например, можно построить небольшую таблицу синусов:
tab = {sin(1), sin(2), sin(3), sin(4), sin(5), sin(6), sin(7), sin(8)}
Для инициализации таблицы как записи, Lua предоставляет следующий синтаксис (т.н. record-style форма конструктора, прим. переводчика):
a = {x=0, y=0}что эквивалентно
a = {}; a.x=0; a.y=0
Не имеет значения, какой конструктор использовался для создания таблицы, всегда есть возможность добавлять и удалять другие поля любого типа:
w = {x=0, y=0, label="console"} x = {sin(0), sin(1), sin(2)} w[1] = "another field" x.f = w print(w["x"]) --> 0 print(w[1]) --> another field print(x.f[1]) --> another field w.x = nil -- удаление поля "x"То есть, все таблицы создаются одинаковыми; конструкторы влияют только на инициализацию.
Every time Lua evaluates a constructor, it creates and initializes a new table. Следовательно, можно использовать таблицы для реализации связных списков (list-style форма конструктора, прим. переводчика):
list = nil for line in io.lines() do list = {next=list, value=line} endДанный код считывает строки со стандартного входного потока и сохраняет их в связном списке в обратном порядке. Каждый узел списка представляет собой таблицу с двумя полями:
value
, которое содержит собственно считанную строку, и next
, являющееся указателем на следующий узел. Следующий код выводит содержимое списка:
l = list while l do print(l.value) l = l.next end(Т.к. список организован по принципу стека (LIFO), строки будут выведены в обратном порядке.) Несмотря на поучительность примера, данная реализация практически не используется в реальных программах на Lua; списки лучше реализовывать как массивы, как можно будет увидеть в Главе 11.
Стили инициализации (record- и list-style) можно применять одновременно в одном конструкторе:
polyline = {color="blue", thickness=2, npoints=4, {x=0, y=0}, {x=-10, y=0}, {x=-10, y=1}, {x=0, y=1} }Приведенный пример также иллюстрирует способ создания вложенных конструкторов для представления более сложных структур данных. Каждый элемент
polyline[1]
, ..., polyline[4]
является таблицей, представляющей запись:
print(polyline[2].x) --> -10
Тем не менее, обе формы конструктора имеют свои ограничения. Например, нельзя инициализировать поля с отрицательными индексами, или со строковыми индексами that are not proper identifiers. Для этих целей существует другой, более общий, формат. В этом формате инициализируемый индекс явно указывается в квадратных скобках, являясь одним из операндов выражения:
opnames = {["+"] = "add", ["-"] = "sub", ["*"] = "mul", ["/"] = "div"} i = 20; s = "-" a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s} print(opnames[s]) --> sub print(a[22]) --> ---Этот синтаксис более громоздкий, но и более гибкий: и list-style и record-style являются вариантами этой общей формы. Конструктор
{x=0, y=0}эквивалентен
{["x"]=0, ["y"]=0}а конструктор
{"red", "green", "blue"}эквивалентен
{[1]="red", [2]="green", [3]="blue"}
Если есть реальная необходимость, чтобы массивы начинались с индекса 0, несложно написать следующее:
days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}Теперь первое значение,
"Sunday"
, имеет индекс 0. Этот ноль не влияет на другие поля, но "Monday"
, естественно, имеет индекс 1, т.к. следует первым в списке значений конструктора; следующие значения располагаются за ним. Тем не менее, я не рекомендую использовать в Lua массивы, начинающиеся с 0. Помните, что большинство функций считают, что массивы начинаются с индекса 1, и следовательно обрабатывают такие массивы некорректно.
Допускается после последнего элемента помещать запятую. Эта завершающая запятая не является обязательной, но всегда корректна:
a = {[1]="red", [2]="green", [3]="blue",}Такая гибкость позволяет легко создавать программы, формирующие таблицы Lua, т.к. нет необходимости обрабатывать последний элемент особым образом.
Наконец, в конструкторе в качестве разделителя всегда можно использовать точку с запятой (;) вместо запятой (,). Мы обычно используем ';' для разделения различных секций конструктора, например для разделения его list-style части от record-style части:
{x=10, y=45; "one", "two", "three"}
Copyright © 2003-2004 Roberto Ierusalimschy. All rights reserved. | Перевод на русский Artem13 |