Перейти к контенту

Внимание. На форуме проводятся технические работы с боковым меню.

_Val_ _Val_

Скриптование


Svoboда

Рекомендуемые сообщения

@abramcumner, 
Я всё это знаю, читал, и слава Богу ещё помню.
Не в этом дело. Сам факт.

Ну вот посчитала lua в этот раз, что #t ==3. Так уж вышло что не 1. К примеру.
Пишу :

t = {1,2,3}
t[2]=nil

По Вашему удалил я его. Совсем. И след простыл. И поверил я что так и есть (к примеру).

 

А lua мне пишет что 3 поля. И я ей ничего не делал. Сама, гадина, решила наплевать на мой nil. Врет и не краснеет.
Теперь я больше не буду ей доверять. Сказали "нет поля" - значит нет. И точка. Пусть свои тройки и дальше пишет. Плевать я хотел.

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение
Посмотри, что выдаст тебе луа

Да мне всё равно что она выдаст. Вернее я знаю что.

Всяких вариантов и сам могу наклепать предостаточно.

Я говорю про конкретный случай.

Оператор # работает с массивом.Так? А ты сам говоришь 

после третьего поля

Т.е. если это массив (раз # так отработал - факт), то есть и второе поле.

И если бы не было второго поля, то t[3] показало бы nil в массиве. А тройка была бы в t[2] Но нет. Показывает 3.

Значит всё-таки массив с тремя полями. И хоть я написал t[2]=nil, никуда оно не удалилось.

Зачистилось значение - да.

Уже не помню где, но читал в доках, что lua до последнего старается сохранить таблицу как массив, а не как хэш.

Выражения "массив" и "хэш" не совсем точно определил, но думаю понятно что я имел в виду.

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@Desertir, 

Смотри. Из-за чего всё началось.

Я сказал что t=nil не удаляет поле, а изменяет его значение. Кто действительно удаляет поле, так это table.remove

Мне сказали что t=nil тоже удаляет поле

Вот я и пытался показать что только  t=nil не перестраивает таблицу. И при итерации поля в ней никуда не деваются в отличии от table.remove.

Вот тут всё прекрасно видно

 

t = {1,2,3,4,5}

for i, v in ipairs(t) do
    print(i,v)
    table.remove(t,i)
end

--> 1	1
--> 2	3
--> 3	5

for i, v in ipairs(t) do
    print(i,v)
    t[i]=nil
end

--> 1	1
--> 2	2
--> 3	3
--> 4	4
--> 5	5

 

Т.е. во втором случае next читает поля и дальше, как ни в чем не бывало.

А значит никуда они не деваются. Просто я даю им новое значение - nil.

С оператором # ещё яснее.

 

for i = 1, #t do
    print(i,t[i])
    table.remove(t,i)
end

--> bla-bla
--> bad argument #1 to 'remove' (position out of bounds)

for i = 1, #t do
    print(i,t[i])
    t[i]=nil
end 

 

Если t=nil отрабатывает нормально, то с table,remove ошибка - "position out of bounds".

Т.е. снова. Хоть я nil и присваиваю, но поля остаются.

 

Да, при повторном использовании полей уже не будет. lua приберет (и то не всегда. показывал уже с t={1.nil,3}).
Но на этом этапе, выходит, никакого удаления полей нет.

Поэтому и называю "изменение значения" а не "удаление".

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение
@abramcumner, Ты в 5.3 тестируешь что-ли?
Да и не важно, пусть в 5.3 и ошибка, но поля-то она правильно удаляет.
 
Как же мне это ещё объяснить?
Во-первых моё выражение "никуда не деваются" не верное. Признаю.
Правильнее сказать "не определяются". И мои примеры с ipairs этому подтверждение.
Во всем остальном остаюсь на своём.
 
Вот то, от чего я отталкиваюсь, и что уже говорил - "lua до последнего старается сохранить таблицу как массив"


t = {}
t[1]=1
--> #t == 1 Всё верно. lua не куда деваться, есть элемент с индексом 1 - значит есть и массив
t[3]=3
--> #t == 1 Сработала неопределённость оператора #. Ну вот решила lua что не хочет добавлять это поле в массив.
t[4]=4
--> #t == 4 Теперь есть три конкретных элемента и одна дырка, значит можно создать массив(подумала lua)
t[6]=6
--> #t == 4 Одну поблажку сделала - пока хватит. Пусть остается как есть (опять же её мысли передаю).
t[8]=8
--> #t == 8 Вот это уже снова похоже на массив. Так тому и быть.
print(#t) --> 8 Фууух. Насилу собрала массив.
t[1]=nil
--> #t == 8 То что зачистили одно поле ещё не значит что буду валить всё то, что так тяжело строила.
t[2]=nil
--> #t == 8 Не легко держать массив, но ничего. Выдюжим и это.
t[3]=nil
--> #t == 8 Безобразие конечно, но пойду на принцип. Моё ведь.
t[4]=nil
--> #t == 8 Караул, грабят. Отбиваюсь как могу.
t[6]=nil
--> #t == 8 Ни грамма сусликам. Нажито непосильным трудом. Не отдам и всё тут.
print(#t) --> 8 Победа

 

Так вот о чем и говорю - НЕ я, сама lua определяет поле [8]=8 при "дырках" от 1-го до 7-го поля.
А как она определяет что поле именно с индексом [8], а не [144] например? Не потому ли, что перед ним есть поля с индексами 1-7?
Значит есть таки поля? Т.е. они определились как поля. И они (пока) не удаляются, а только зачищаются их значения.
 
И я говорю, что записав t=nil мы только лишь изменяем значение. Нельзя сказать что я удаляю поле. Не нам это решать а lua
Оно может ей пока и понадобиться, как я только что под спойлером показал.
 
Именно об этом битый ... толкую.
А остальное - это уже совсем другая история. Л.Каневский.
Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@CRAZY_STALKER666, 
В крайнем случае, если стоит расширение lua, можно и самому организовать свой динамический аналог game_story_ids.
И там хранить типа sid-ов объектов.
Я так делал когда-то.Если интересно.

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

Этот вариант я тоже тогда рассматривал.
Но если ты будешь спавнить что-то через секцию alife():create("any_section", vector():set(... и т.д. и нужно будет это позже удалять.
Снова for i=1,65534 ?

Поделиться этим сообщением


Ссылка на сообщение

@CRAZY_STALKER666, 

Если ты будешь спавнить все объекты, которым необходимо назначать sid через all.spawn, то тогда я ни о чем.

 

Я о том что будет, если будешь спавнить что-то по имени секции динамически, т.е. (например) 

alife():create("stalker", vector():set ... bla-bla

И тебе позже нужно будет найти именно этого сталкера из кучи остальных, так же заспавненных.

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@Zander_driver, 

На самом деле всё не так уж и плохо.
Оператор '#' прекрасно работает с "правильными" массивами.
Осталось только нам научиться работать с массивами также правильно :)
table.insert и table.remove сделаны специально для этого и должны помочь.
 
А поведение оператора '#' и его будущее в других случаях до сих пор не так однозначно.
В PiL3 об этом написано в разделе 3.5. Оператор длины
Особенно мне "нравиться" фраза самого автора:
"поэтому большую часть времени оператор длины безопасен для использования"
Как тебе такое? :):(
Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

Да, в 5.1 не хватает этого метода.

Впрочем можно написать функцию типа :

function table.len(t)
	local n = 0
	for _ in ipairs(t) do
		n = n + 1
	end
	return n
end

А заодно не хватает __pairs и __ipairs. Да и goto, при аккуратном использовании, помогает крепко сокращать код  :)

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

Почему при спавне НПЦ скриптом в его имени к основному добавляются какие-то рандомные цифры?

Вот почему, извините начальство форума за не очень пристойное слово, хочется {игнорировать} всякие призывы о помощи, и не тратить силы на распинания по сути.

CRAZY_STALKER666 ты же поставил "Спасибо" к моему посту http://www.amk-team.ru/forum/topic/6185-skriptovanie/?p=1020661, т.е. ты должно быть его прочитал.

А если это так, то ты не мог не заметить, что я в этом посте рассказывал про "цифры" в имени объекта.

 

В то время, когда я начинал моддить, не было столько исчерпывающей информации как сейчас. Цеплялись за любые намеки. А тут...

"Абыдно, да?" ("Кавказская пленница")

 

"Начальство" в специально отведенном месте постоянно рыдает по тому же самому поводу. Не успевает жилетки менять. dc

Изменено пользователем Dennis_Chikin

Поделиться этим сообщением


Ссылка на сообщение

@FonSwong, 

Таблицы, функции, потоки и пользовательские данные (userdata) - это объекты: переменные фактически не содержат их значений, только ссылки на них. Присвоение, передача параметров и возврат из функций всегда манипулируют ссылками на эти значения; эти операции не подразумевают никакого типа копирования. 

Вот тут:

ignore_tbl[back_level] = point_tbl
ты создаешь ещё одну ссылку(имя) на таблицу(объект) с именем point_tbl.
Таких ссылок(имен) может быть множество, а объект один и тот же.

Изменено пользователем Nazgool
  • Полезно 1

Поделиться этим сообщением


Ссылка на сообщение
как мне сделать дубликат
Как тебе уже сказали - именно перебирать и переписывать каждое вложение.
Есть не мало вариантов функций сделать это.
Но при условии, что у тебя достаточно простая таблица.
Сделать полное копирование сложной таблицы (реально полное) проблематично.
(По крайней мере необходимости в этом не было, поэтому не делал. Да и не буду)
Поясню что я подразумеваю под простой сложной таблицей и почему проблематично.
Всё дело в ключах таблицы.
Если ключи НЕ объекты - то всё нормально.
Вот вариант копирования простой таблицы, в котором ключи не объекты, а строки или числа.
Если значением ключа будет таблица, то создается копия этой таблицы.
И так рекурсивно для всех степеней вложенности :

function table.copy (tab)
    assert(type(tab) == 'table' , [[bad argument #1 to 'table.copy' => table expected, got ]] .. type(tab))
    
    local function tcopy(src)
        if type(src) ~= 'table' then
            return src
        end
            
        local new = {}
        
        for k, v in pairs(src) do
            new[k] = tcopy(v)
        end
        
        return new
    end
        
    return tcopy(tab)
end

 

Вот сложнее вариант.

Если значением есть таблица, для которой установлена метатаблица, то нужно скопировать эту метатаблицу.
Поэтому немного расширенный вариант будет выглядеть так :

function table.copy (tab, meta)
    assert(type(tab) == 'table' , [[bad argument #1 to 'table.copy' => table expected, got ]] .. type(tab))
        
    local function tcopy(src, meta)
        if type(src) ~= 'table' then
            return src
        end
            
        local new = {}
        
        for k, v in pairs(src) do
            new[k] = tcopy(v, meta)
        end
        
        if meta then
            setmetatable(new, tcopy(getmetatable(src), meta))
        end
        
        return new
    end
        
    return tcopy(tab, meta)
end

 

И вот теперь про самый сложный вариант и про "проблематично".
А если ключем будет таблица (не буду брать функции, потоки и тем более userdat-у).
По аналогии нужно копировать и эту таблицу-ключ.
Для этого нужно изменить :

new[k] = tcopy(v, meta)
-- на
new[tcopy(k, meta)] = tcopy(v, meta)

 

НО. При этом будет создана новая ключ-таблица, для которой не назначено никакого идентефикатора.
Т.е. она будет анонимна. Я вот о чем :

 
Например есть такой код :
t = {b=3}
x = {a=1, [t]=2}

y = table.copy(x)
Вариант с кодом - new[k] = tcopy(v)
В "new[k]"  будет использована ссылка на таблицу с именем "t".
Поэтому можно увидеть :
print(y[t]) --> 2
Но если использовать вариант с - new[tcopy(k, meta)] = tcopy(v, meta), то :
print(y[t]) --> nil
Обращаясь y[t] мы обращаемся к полю таблицы, именем которого является объект!!! с именем "t" .
Но в ключе была создана новая таблица(объект) - new[tcopy(k, meta)] - которая уже не является таблицей с именем "t".
Поэтому print(y[t]) --> nil - Действительно, ключ был переписан новым безымянным объектом.
 
Т.е. такое копирование ограничивает функционал, т.к. теперь нет поля y[t], к которому можно было просто обратиться.
И можно ли назвать подобное копирование копированием?
А если таких ключей множество, то при переборе for k, v in pairs как определить что этот ключ-таблица "k" именно то что нам нужно, если они все безымянны?
В функции копирования создавать сопоставления? Теоретически можно. А практически нужно?

Изменено пользователем Nazgool
  • Нравится 1
  • Полезно 1

Поделиться этим сообщением


Ссылка на сообщение

@Kirgudu, Про оператор "#" я не так давно уже рассказывал. Это не надежно.

Поэтому всё-таки стоит пользоваться специально созданными для этого функциями ipairs и table.insert(remove)

Напомню

 

local t = {nil,nil,3}

for i = 1, #t do
    print(t[i])
end

--> nil
--> nil
--> 3

for i, v in ipairs(t) do
    print(i,v) --> ничего не печатает
end 
И хотя я считаю что работа оператора # более правильная, чем ipairs (как ни крути, но это массив. есть ключи 1.2.3 и есть соответствующее им lua-значения), он не гарантирует всегда правильной работы.
Но разработчики считают что nil не должен быть значением, поэтому пусть так и будет.
А в специальных случаях (как то мой пример выше) никто не запретит пользоваться # :)

 

 

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@Serge!, 

 

она просто рассчитана на неассоциированный массив без вложений

Т.е. копируем массив всё-таки.
И если до копирования работать с массивом правильно, посредством функции table.remove и др., то у Вас в массиве никогда не будет полей со значением nil.
Поэтому и копирование с помощью irairs создаст точную копию такого массива.

И оператор # работает с таким правильным массивом тоже совершенно правильно.
И будет работать правильно, пока как мы своими неправильными действиями не испортим массив, и не начнутся казусы с этим оператором.

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

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@Malandrinus,

Абсолютно согласен с тем, что массивы с nil-ами это зло.

А необходимость копирования таблиц (с nil-ами или без них) можно определить только после того, как будут известны общие цели и задачи скрипта.
Но в это мы не посвящены, поэтому принимаем задачу как есть - т.е. нужно копировать.
И насчет того, чтобы "вообще убрать такой массив" я уже неоднократно говорил.
Если работать с массивами правильно, то такой необходимости не возникнет в принципе.
 
Хоть в сталкере используется lua 5.1.4, но компилируется код с помощью luajit 1.1.5 (или ошибаюсь?)
И если у тебя есть возможность протестировать оба варианта (for i=1,#t и ipairs) в  luajit, то заметной разницы в скорости выполнения ты не увидишь.
Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@Serge!, 

Ну обсуждалось же уже. Ладно.

Вот случай, описанный тобой.
Есть массив, похожий на тот, что ты упоминал :
local t = {nil,2}
1-я проблема. Определять поля нужно сразу
local t = {}
t[1]=nil
t[2]=2
Так уже не работает!
 
В этом массиве опрелено только одно поле по индексу [2].
В процессе (например) нужно сначала добавить поле с индексом [3]
 
2-я проблема. local t = {nil,2,nil} - третий nil как ты говоришь "должен присутствовать", но валит весь массив.
И ты не сможешь его перебирать, т.е. и уже определенное значение в поле [2] пропадает.
 
Поэтому нужно оставлять в таком виде для целостности массива
local t = {nil,2}
и теперь нужно добавиить поле [3], как у тебя "позже в процессе инициализации"

t[3]='a'
3-я проблема. Массив валиться с этим добавлением.
 
Пока хватит. И так проблема на проблеме. Кому это нужно?

 

 

 

И да. При использовании функций-итераторов выполняются некоторые дополнительные инструкции, но в контексте luajit время их выполнения минимизируется по сравнению с (как уже выяснилось) не 100%-но надежным оператором #.

Но в контексте надежности кода, использование стандартных методов намного предпочтительнее, чем гонка за сомнительной прибавкой в скорости. Тем более, как ты сам сказал, при работе с небольшими таблицами сталкера.

Изменено пользователем HellRatz

Поделиться этим сообщением


Ссылка на сообщение
в чём проблема?

Вот в чем.

Если почитать описание функции pairs, она использует как итератор функцию next.

А для функции next записано :

Порядок следования индексов неопределен, даже для числовых индексов. (Для прохождения по таблице в числовом порядке, используйте числовой for или функцию ipairs.) 

Т.е. разрабы и сами не уверены, что pairs верно распарсит правильный массив.

Да и когда кто-то будет читать твой код, то увидев ipairs сразу поймет что парсится массив, а не всё подряд.

 

Изменено пользователем Nazgool

Поделиться этим сообщением


Ссылка на сообщение

@abramcumner, 

Изначально речь шла о копировании массива. Правильно индексированного, без "дырок" списка.

В функции использовался pairs.

Как можно копировать такой массив с помощью pairs если:

Порядок следования индексов неопределен, даже для числовых индексов !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

И

разрабы и сами не уверены, что pairs верно распарсит правильный массив.

Я ни слова не сказал о том, что он не обойдет всю таблицу. Обойдет, конечно же обойдет. Но как?

Обойдет как написано в первой цитате. Т.е. а кто его знает как.

И что же мы скопируем?

 

Поэтому - ipairs

Кому не нравиться - тому _G.ipairs

А кому и это не нравиться, тогда local kak_ni_kruti_vse_ravno_ipairs = ipairs

Изменено пользователем Nazgool
  • Согласен 1

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...