2013-10-10 42 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 [I]在這裏列出的前兩個功能,我不明白他們爲什麼引用_G [resTable [I] ]因爲我沒有看到被寫入_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]

是第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功能。它的主要限制是它只能保存字符串,布爾值是一個數字,但通常在學習時這就足夠了。如果您需要更先進的技術,系列化你可以參考Lua WIKI page on table serialization

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) 

你可以用下面的語句進行測試。

+0

我應該在他書中的後續段落中提到,如果要保存的數據是其他內容,_(除了字符串或數字)_函數將開始失敗,如果變量是表格。表的最大問題是遍歷表的深度。他然後主張使用JSON庫對錶對象和JSON編碼字符串之間的信息進行編碼或解碼。 – PHazer

+0

此外,作者正在通過解決問題的最簡單功能問題逐步解決問題,指出缺陷,然後在本章進行時引入更全面的功能。這可能或不是爲什麼這些功能存在問題。他的最終解決方案是一個將表格保存爲JSON編碼字符串的函數。儘管如此,對於像我這樣的新手來說,這種方法往往會讓人迷惑。 – PHazer

+0

@PHAZer我不能沒有看到它就判斷,但我討厭那些過分簡化事物的書:它們往往會讓學習變得更加困難,因爲讀者,特別是新手,最終必須忘掉壞習慣或錯誤的方法。 –

相關問題