Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为Lua声明变量和范围问题_Lua_Scope - Fatal编程技术网

为Lua声明变量和范围问题

为Lua声明变量和范围问题,lua,scope,Lua,Scope,我是的开发负责人,我们使用Lua作为脚本语言,允许玩家编写自己的定制机器人飞船 在Lua中,您不需要声明变量,并且所有变量都默认为全局范围,除非另有声明。这导致了一些问题。以以下代码段为例: loc = bot:getLoc() items = bot:findItems(ShipType) -- Find a Ship minDist = 999999 found = false for indx, item in ipairs(items) do lo

我是的开发负责人,我们使用Lua作为脚本语言,允许玩家编写自己的定制机器人飞船

在Lua中,您不需要声明变量,并且所有变量都默认为全局范围,除非另有声明。这导致了一些问题。以以下代码段为例:

loc = bot:getLoc()
items = bot:findItems(ShipType)     -- Find a Ship

minDist = 999999
found = false

for indx, item in ipairs(items) do           
   local d = loc:distSquared(item:getLoc())  

   if(d < minDist) then
      closestItem = item
      minDist = d
   end
end

if(closestItem != nil) then 
   firingAngle = getFiringSolution(closestItem) 
end
loc=bot:getLoc()
items=bot:findItems(ShipType)--查找船舶
Minist=999999
发现=错误
对于indx,IPAIR中的项目(项目)do
本地d=loc:distSquared(项:getLoc())
如果(d
在这个代码段中,如果findItems()没有返回任何候选项,那么closestItem仍然会引用它上次找到的任何一艘船,在此期间,这艘船可能已经被击毙。如果飞船被杀死,它将不再存在,getFiringSolution()将失败

你发现问题了吗?我的用户也不会。这是微妙的,但有戏剧性的效果

一种解决方案是要求声明所有变量,并将所有变量默认为局部范围。虽然这种更改不会使程序员无法引用不再存在的对象,但会使无意中引用对象变得更加困难

有没有办法告诉Lua将所有变量默认为本地范围,和/或要求声明它们?我知道其他一些语言(例如Perl)也有这个选项

谢谢


这里有很多好答案,谢谢

我决定使用Lua‘strict’模块的稍加修改的版本。这似乎让我达到了我想要达到的目的,我将对其进行一些修改,以改进消息,使其更适合我的特定环境。

Sorta

在Lua中,globals概念上位于globals表
\u G
(现实有点复杂,但从Lua的角度看,没有办法告诉AFAIK)。与所有其他Lua表一样,可以将
\uuu newindex
元表附加到
\u G
以控制如何向其添加变量。让这个
\uuu newindex
处理程序在有人创建全局索引时执行您想执行的任何操作:抛出错误,允许它,但打印警告,等等


要处理
\u G
,使用
setfenv
最简单、最干净。请参阅。

没有设置此行为的选项,但标准安装中提供了一个模块“strict”,它正是这样做的(通过修改元表)。 用法: 要求“严格”


有关更深入的信息和其他解决方案:,但我建议使用“strict”。

事实上,带有对ship的陈旧引用的额外全局变量将足以防止GC丢弃对象。因此,可以在运行时通过注意到船现在“死了”并拒绝对它做任何事情来检测它。它仍然不是合适的船,但至少你没有坠毁

您可以做的一件事是将用户脚本保存在一个沙箱中,每个脚本可能有一个沙箱。通过对沙盒的环境表或元表的正确操作,您可以安排在调用用户代码之前(或之后)放弃沙盒中的所有或大部分全局变量

在调用后清理沙箱的好处是丢弃对不应该挂起的东西的额外引用。这可以通过保留允许保留在环境中的字段的白名单,并删除所有其余字段来实现

例如,下面实现了对用户提供的函数的沙盒调用,环境中只包含为每个调用提供的新暂存表后面的白名单名

-- table of globals that will available to user scripts local user_G = { print=_G.print, math=_G.math, -- ... } -- metatable for user sandbox local env_mt = { __index=user_G } -- call the function in a sandbox with an environment in which new global -- variables can be created and modified but they will be discarded when the -- user code completes. function doUserCode(user_code, ...) local env = setmetatable({}, env_mt) -- create a fresh user environment with RO globals setfenv(user_code, env) -- hang it on the user code local results = {pcall(user_code, ...)} setfenv(user_code,{}) return unpack(results) end --可供用户脚本使用的全局表 本地用户\u G={ print=_G.print, 数学, -- ... } --用户沙箱的元表 本地环境mt={{uuuu索引=用户} --在沙箱中调用函数,沙箱中的环境中包含新的全局 --可以创建和修改变量,但当 --用户代码完成。 函数doUserCode(用户代码,…) local env=setmetatable({},env_mt)——使用RO globals创建一个新的用户环境 setfenv(用户代码,env)--将其挂在用户代码上 本地结果={pcall(用户代码,…)} setfenv(用户代码,{}) 返回解包(结果) 结束 如果需要的话,可以通过将全局表向后推一次元表访问来扩展它,使其成为只读的

注意,一个完整的沙盒解决方案还将考虑如何处理意外地(或恶意地)执行无限(或仅仅很长)循环或其他操作的用户代码。这方面的一般解决方案是偶尔讨论的话题,但好的解决方案是困难的。

“本地默认情况下是错误的”。请看

你需要采取某种全球环境保护措施。有一些静态工具可以做到这一点(还不太成熟),但最常见的解决方案是基于
\uuuu index
\uuu newindex
中的
\uu G
元表使用运行时保护

Shameles plug:此页面也可能有用:


注意,在讨论嵌入到swf中的Lua时,所描述的技术(请参阅)适用于通用Lua。我们在工作中的生产代码中使用了类似的东西。

顺便说一句,你有什么好的理由在if语句中添加额外的大括号吗?好的,在你提出问题之前,我会回答它们是必需的。但现在我必须回答,省略paren对我来说是错误的!当然,这是个人的喜好。但重要的是要记住Lua不是C或Pascal或其他任何东西。Lua就是Lua,要有效地使用它,您必须按原样使用它,而不是把它当作其他程序的糟糕替代品