[英]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.