2013-10-10 2 views
7

Я изучаю Lua из книги, и я НЕ программист. Я пытаюсь сохранить таблицу данных в файл, используя следующие функции (которые были скопированы непосредственно из книги), но функция получает ошибку при попытке получить строку из _G [resTable]. Зачем?Lua: Когда и как писать таблицы в _G

function readFromFile(filename,resTable) 
    local hfile = io.open(filename) 
    if hfile == nil then return end 
    local results = {} -why is this table here? 
    local a = 1 
    for line in hfile:lines() do-- debug shows this loop doesn't run (no lines in hfile?) 
     _G[resTable[a]] = line 
     a = a + 1 
    end 
end 

function writeToFile(filename, resTable) 
    local hfile = io.open(filename, "w") 
    if hfile == nil then return end 
    local i 
    for i=1, #resTable do 
     hfile:write(_G[resTable[i]])--bad argument #1 to 'write' (string expected, got nil) 
    end 
end 

«WriteToFile» получает ошибку при попытке:. Написать _G [resTable [я]] В двух предыдущих функций, перечисленных здесь, я не понимаю, почему они ссылаются _G [resTable [я] .], так как я не вижу какой-либо код, который при записи в _G

Так вот порядок исполнения:

local aryTable = { 
"Score", 
"Lives", 
"Health", 
} 

readFromFile("datafile", aryTable) 

writeToFile("datafile", aryTable) 

и я получаю сообщение об ошибке:

bad argument #1 to 'write' (string expected, got nil) 
stack traceback: 
[C]: in function 'write' 
test.lua:45: in function 'writeToFile' 
test.lua:82: in main chunk 
+0

В чем состоит ваш файл данных? – interjay

+0

В настоящее время «datafile» ничего не имеет – PHazer

+0

... так что вы ожидаете от 'readFromFile'? – interjay

ответ

0

Это не обобщенные функции «чтение/запись любой таблицы из/в любой файл». Они, по-видимому, ожидают имя глобальной таблицы в качестве аргумента, а не таблицы [ссылки на локальную]. Они выглядят как одноразовое решение для очень конкретной проблемы, которая, как правило, появляется в книгах. :-)

Ваши функции не должны ничего делать с _G. Я не имею ссылка на API под рукой, но цикл чтения должен делать что-то вроде

resTable[a] = line 

и цикл записи будет делать

hfile:write(resTable[i]) 

Выбросьте, что местные «результаты» таблицы тоже. :-)

+0

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

+0

... и таблица «результатов» тайны не привили мне никакой уверенности. – PHazer

+1

Автореферат «readFromFile»: _ В вашем приложении количество переменных, которые вы могли бы сохранить, может отличаться для каждого приложения. Вы никогда не узнаете порядок сохранения ваших данных и если порядок сохранения данных или чтение данных изменяется, у вас могут быть значения, которые попадают в неправильные переменные. Итак, что мы собираемся сделать, чтобы исправить эту проблему, есть таблица с данными и имена в ней. Это обеспечит нам гибкость в дальнейшем расширять его в будущем. Затем он показывает функцию readFromFile. – PHazer

0

Этот код считывает и записывает данные из файла в глобальные переменные, имена которых указаны в aryTable. Поскольку ваш файл пуст, readFromFile фактически не устанавливает значения переменных. И тогда writeToFile терпит неудачу при попытке получить значения переменных, потому что они не были установлены.

Попробуйте поместить данные в файле, так что переменные действительно получить набор, или установить переменные значения себя перед записью их в файл (например, Score = 10 и т.д.)

+0

Вы определили мою основную проблему с авторской записью. Мне показалось очевидным, что с «readFromFile» возникла проблема с пустым файлом данных, но нигде в этой главе он не упомянул о любом способе записи данных в файл данных за пределами использования 'writeToFile'. – PHazer

+0

Кроме того, когда я помещаю некоторые строки данных в файл данных напрямую (текстовый редактор), функция просто стирает их все равно. – PHazer

3

По-видимому, автор реализовал способ экономии список глобальных переменных для их восстановления и восстановления.

Функция writeToFile ожидает имя файла и список имен глобальных переменных (resTable). Затем он открывает имя файла для записи и перебирает предоставленные названия:

for i=1, #resTable do 
    hfile:write(_G[resTable[i]]) 
end 

в этом цикле resTable[i] является я-е имени и _G[resTable[i]] является соответствующим значением, взятое из таблицы _G, которая хранит все глобал , Если глобальный с этим именем не определен, _G[resTable[i]] вернет nil, что является причиной неудачи, с которой вы столкнулись. Таким образом, вы должны предоставить resTable, который заполняется именами существующих глобальных переменных, чтобы избежать этой ошибки.

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

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

local a = 1 
for line in hfile:lines() do 
    _G[resTable[a]] = line 
    a = a + 1 
end 

проблема является много раз:

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

Кроме того, local results = {} бесполезен, и в обеих функциях дескриптор файла hfile не закрыт. Это очень плохая практика: она может растрачивать системные ресурсы, и если ваш скрипт не работает, часть якобы написанных данных никогда не сможет попасть на диск, поскольку он может оставаться в каком-то буфере. Файловые дескрипторы автоматически закрываются, когда скрипт заканчивается, но только если он заканчивается разумным способом.

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


Если вы хотите быстро и грязный способ сохранить и восстановить некоторые глобал вы могли бы использовать это:

function writeToFile(filename, resTable) 
    local hfile = io.open(filename, "w") 
    if hfile == nil then return end 
    for _, name in ipairs(resTable) do 
     local value = _G[name] 
     if value ~= nil then 
      hfile:write(name, " = ") 
      local vtype = type(value) 
      if vtype == 'string' then 
       hfile:write(string.format("%q", value)) 
      elseif vtype == 'number' or vtype == 'boolean' then 
       hfile:write(tostring(value)) 
      else 
       -- do nothing - unsupported type 
      end 
      hfile:write("\n") 
     end 
    end 
    hfile:close() 
end 

readFromFile = dofile 

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

Вы можете протестировать его со следующими утверждениями:

a = 10 
b = "20" 
c = "hello" 
d = true 
print(a, b, c, d) 
writeToFile("datafile", { "a", "b", "c", "d" }) 
a, b, c, d = nil 
print(a, b, c, d) 
readFromFile("datafile") 
print(a, b, c, d) 

Если вам нужны более сложные методы сериализации вы можете обратиться к Lua WIKI page on table serialization.

+0

Я должен упомянуть, что в последующем абзаце в его книге он признает: «Если данные, которые нужно сохранить, - это что-то еще, _ (помимо строк или чисел), функции начнут терпеть неудачу, и более того, если переменная является таблицей , Самая большая проблема с таблицами повторяется в глубинах таблицы. Затем он выступает за использование библиотеки JSON для кодирования или декодирования информации между объектом таблицы и строкой, кодированной JSON. – PHazer

+0

Кроме того, автор по-разному работает над проблемами с простейшими функциями для решения проблемы, указывая на ловушки, а затем вводит более полные функции по мере продвижения главы. Это может быть или не быть, почему эти функции имеют проблемы, как есть. Его конечное решение - это функция, которая сохраняет таблицы как строки, закодированные JSON. Тем не менее, для новичков, подобных мне, этот подход, как правило, путает. – PHazer

+0

@PHazer Я не могу судить, не видя этого, но я ненавижу книги, которые упрощают вещи: они, как правило, усложняют обучение, потому что читатель, особенно новичок, в конце концов должен отвязывать вредные привычки или ложные подходы. –

Смежные вопросы