Lua Table Gap aviod - PullRequest
       29

Lua Table Gap aviod

0 голосов
/ 05 марта 2019

Почему таблица lua (перефразирует?) Позволяет избежать пробелов при использовании другого синтаксиса?

проверить функцию

d = require "core/modules/inspect"

Case1: стандартный синтаксис 1-й элемент - это пробел

t = {1,2,3}
t[1] = nil
d(t)
__________
{ nil, 2, 3 }

Case2: с синтаксисом скобок нет пробелов

 t = {
    [1] = 1,
    [2] = 2,
    [3] = 3,
}
t[2] = nil
d(t)
__________
{ 1,
  [3] = 3
}

Case3: динамический массив - без пробелов

t = {}
t[1] = 1
t[2] = 2
t[3] = 3
t[2] = nil
d(t)
__________
{ 1,
  [3] = 3
}

Case4: динамический массив при установке нуля в1-й элемент - это пробел

t = {}
t[1] = 1
t[2] = 2
t[3] = 3
t[1] = nil
d(t)
__________
{ nil, 2, 3 }

Case5: с синтаксисом в скобках установлен ноль, в 1-м элементе все еще нет пробелов

t = {
    [1] = 1,
    [2] = 2,
    [3] = 3,
}
t[1] = nil
d(t)
__________
{
  [2] = 2,
  [3] = 3
}

1 Ответ

0 голосов
/ 05 марта 2019

Lua не определяет поведение для оператора длины для непоследовательных индексов, но принимает ответ на Почему оператор длины (#) Lua возвращает неожиданные значения? входит в то, что практически происходит в стандартной реализацииЛуа 5.2.Тем не менее, этот ответ сам по себе не полностью объясняет поведение, поэтому здесь приведено индивидуальное объяснение с использованием стандартной реализации Lua 5.3.5.

Примечание: я использую оператор длинычтобы четко показать случаи, когда возникают отверстия.Относительно того, как это применимо к используемой вами функции проверки, из того, что я вижу в ее поведении, она просто явно указывает любые индексы вне диапазона 1 <= index <= # table. </em>

Случай 1:

> t = {1,2,3}
> t[1] = nil
> print(#t)
3

Размер части массива таблицы Lua основан на степени двойки - , за исключением , когда таблица построена с предварительно установленными значениями,Строка t = {1,2,3} создает таблицу с частью массива размером 3. Когда вы выполняете t[1] = nil, у части массива нет оснований для изменения размера, поэтому ее размер остается равным 3. Поскольку последний элемент в части массиване ноль, и часть хеша пуста, возвращается размер массива - 3.

Случай 2:

> t = {[1] = 1, [2] = 2, [3] = 3}
> t[2] = nil
> print(#t)
1

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

Случай 3:

> t = {}
> t[1] = 1
> t[2] = 2
> t[3] = 3
> t[2] = nil
> print(#t)
1

Когда квадратные скобки используются внеконструктор, Lua проверит числовые индексы, чтобы увидеть, должны ли они входить в массив или хеш.В этом случае каждый из индексов будет входить в часть массива, но поскольку эти значения определены вне конструктора, размер массива будет определяться при присваивании на основе степеней двойки.Таким образом, после первых трех назначений часть массива будет иметь размер 4. Назначение nil не вызывает изменение размера, поэтому оно остается равным 4. Таким образом, когда применяется оператор длины, он видит, что окончательное значениев пространстве массива ноль, и поэтому он выполняет двоичный поиск индекса перед первым значением ноль, которое равно 1.

Случай 4:

> t = {}
> t[1] = 1
> t[2] = 2
> t[3] = 3
> t[1] = nil
> print(#t)
3

Этоcase точно такой же, как и в случае 3, но бинарный поиск обнаруживает, что t[2] не равен nil и поэтому не учитывает значения ни в одном индексе до 2. Это приводит к продолжению поиска по индексам после 2, что завершаетчто длина равна 3.

Случай 5:

> t = {[1] = 1, [2] = 2, [3] = 3}
> t[1] = nil
> print(#t)
0

Это похоже на Случай 2 в том смысле, что элементы таблицы являются элементами хеш-частиТаблица.В этом случае, однако, процесс поиска приводит к 0. Это потому, что перед попыткой двоичного поиска функция определяет, в каком диапазоне целочисленных индексов она должна искать.Наличие нулевого значения в первом индексе означает, что цикл, который определяет диапазон, не запускается.Для получения дополнительной информации о том, как работает этот процесс поиска, вы можете увидеть функцию здесь .Когда я говорю, что цикл не запускается, я имею в виду условие while: !ttisnil(luaH_getint(t, j)).

Бонусный случай:

> t = {}
> t[1] = 1
> t[4] = 4
> print(#t)
1
> g = {}
> g[1] = 1
> g[3] = 3
> g[4] = 4
> print(#g)
4

В случае 3Я упомянул тот факт, что Lua решает, поместить ли числовой индекс в часть массива или в часть хеша.В приведенной выше таблице t индекс 1 находится в части массива, а 4 - в хэш-части.Таким образом, возвращаемая длина равна 1. В случае g все значения помещаются в часть массива.Это связано с тем, что при назначении значений индексам Lua пытается оптимально изменить размер части массива.Для лучшего понимания этого процесса изменения размера вы можете просмотреть источник здесь .

...