簡體   English   中英

Lua:何時以及如何將表寫入_G

[英]Lua: When and how to write tables to _G

我正在從書中學習Lua,而我不是程序員。 我正在嘗試使用以下函數(直接從本書中復制)將數據表保存到文件中,但是當嘗試從_G [resTable]獲取字符串時,該函數出錯。 為什么?

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

顯然,作者已經實現了一種將全局變量列表保存到文件並恢復它們的方法。

函數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函數執行腳本來讀取它們。 它的主要限制是它只能保存字符串,布爾數字,但通常這在學習時就足夠了。

您可以使用以下語句對其進行測試:

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頁面

這些不是通用的“從/向任何文件讀/寫任何表”功能。 他們顯然希望將全局表名稱作為參數,而不是[對本地]表本身的引用。 它們看起來像是一種一次性解決方案,可以解決一個非常具體的問題,這些問題往往會出現在書本中。 :-)

你的函數不應該用_G做任何事情。 我沒有方便的API參考,但讀取循環應該做類似的事情

resTable[a] = line

而寫循環將會這樣做

hfile:write(resTable[i])

扔掉那個本地的“結果”表。 :-)

此代碼將文件中的數據讀寫到全局變量中,這些變量的名稱在aryTable中指定。 由於您的文件為空,因此readFromFile實際上並未設置變量值。 然后writeToFile在嘗試獲取變量值時失敗,因為它們尚未設置。

嘗試將數據放入文件中以便設置變量,或者在將變量值寫入文件之前自己設置變量值(例如Score = 10等)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM