【问题标题】:How to get variables that not declared yet but will declared soon?如何获取尚未声明但即将声明的变量?
【发布时间】:2015-10-04 13:15:59
【问题描述】:

如何获取尚未声明的变量?

下面是简单的例子:

a = b
b = 123

这两行我想要的是a 123。但是obv它不起作用。

我知道获得答案a = 123 的简单方法是剪切第一行并将其粘贴到第二行以下。

但我遇到了一些问题。我需要一些像“WillDeclaredVar()”这样的函数,我可以这样使用:

a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)

所以我可以得到答案“123”。

或者有什么内置函数可以让我做类似的事情?

===

我认为 timrau 提供的链接并没有说明我的情况。关键是如何获取“尚未声明的变量”。

===

添加实际代码:

triggerCount = 0 -- Counting number of 'Trigger' function
local Trigger = function (t)
triggerCount = triggerCount + 1
return Trigger (t)
end


-- following Triggers are same as while statement.
-- following Triggers doing: Add 1 MarineCount until get 64000 MarineCount



Trigger { -- Here the Trigger function. Now triggerCount = 1.
    players = {P1}
    actions = {
        SetDeaths(P1, Add, 1, "Terran Marine")
    },
flag = {preserved},
}
Portal(LoopStart);
-- function Portal(VariableName) returns VariableName = triggerCount. So LoopStart = 1.

Trigger { -- Now triggerCount = 2.
    players = {P1}
    actions = {
        LinkList(LoopEnd, LoopStart);
-- function LinkList(From, To) changes 'From' Trigger's next pointer to the 'To' Trigger.
-- But now the problem happens. Because 'LoopEnd' is not declared yet.
    },
flag = {preserved},
}


Trigger { -- Now triggerCount = 3.
    players = {P1}
    conditions = {
        Deaths(P1, Exactly, 64000, "Terran Marine");
    }
    actions = {
        _LinkList(LoopEnd);
        -- Reset LoopEnd's next pointer(= LoopEscape) if MarineCount hits 64000
    },
flag = {preserved},
}
Portal(LoopEnd); -- LoopEnd = 3.
  1. 更改触发器顺序会破坏触发器逻辑(while 语句)。

  2. 我想要的只是轻松编码。说白了,我不需要解决这个问题(get undeclared var)。我可以想象一些避免它的方法。但是如果我使用这些方式,那么编码工作会非常复杂,编码的难度会大大增加。困难让我最近几个月停止了编码。

【问题讨论】:

  • 如何获取不存在的变量?你没有。你的例子没有意义。只需将a = 移动到b = 行下方。完毕。您的示例绝不解释您为什么需要这个。请给出一个真实世界的示例,该示例不是通过简单地重新排序行来轻松修复且没有副作用的。
  • 这闻起来很像XY Problem。你为什么需要这个?你真正的问题是什么?
  • @Mud 在实际代码中,有很多函数。这些功能需要保持正确的顺序并且不要移动。这都是关于 sc1 地图制作的。所以函数(和/或触发器)的顺序非常重要。特别是当我试图管理整个函数的链接列表时。所以是的。试图获取一个不存在的变量通常是不可能的。但我问这个问题的原因是:
  • 1.我是 Lua 的大人物,所以我想也许有一些方法可以避免它。 2.有人用python做了8~900行。他说很难让它真正发挥作用。我希望你不会感到语言障碍

标签: lua


【解决方案1】:

如何获取尚未声明的变量?

时间短,你不能。

您的示例代码没有解释问题的动机,因为:

a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)

可以简单地重新排列成这样:

sheepCount = 123
b = sheepCount
a = WillDeclaredVar(b)
print(a)

如果您展示了您要解决的实际问题(以避免XY problem),那么回答您的问题会更容易。

但是,如上所述,我们可以注意到的事情很少。

首先,您需要区分声明一个变量和给它一个值。在 Lua 中你可以说:

local b

b 声明为局部变量,这可能会在堆栈帧中为其创建一个插槽,并让您在给它一个值之前将闭包绑定到它。但是,该行:

a = WillDeclaredVar(b)

将传递WillDeclaredVar b 当前 具有的值,并且由于b 被分配了一个新值,a 无法追溯更改。这永远不会发生。 aWillDeclaredVar 甚至都不知道 b 的存在,它们在调用点收到它包含的值。

但是,您可以将变量 b 绑定到一个闭包,该闭包将在需要时获取 b 的当前值。

-- declare b before giving it a value, aka "forward reference"
local b
a = function() return b end
sheepCount = 123
b = sheepCount
print(a()) -- call a to get b's current value

另一种方法是让b 成为一个全局 变量,它实际上只是你的环境表的一个键,所以你可以说:

a = WillDeclaredVar('b')

并让a 成为可以在需要时获取__ENV['b'] 的当前值的对象。

但是,它们都不支持这种语法:

print(a)

a 需要是一个函数,它在需要时查找b 的值,而不是简单地保存先前计算的值。您可以在这个特定的实例中(即a 需要可转换为字符串)通过创建实现__tostring 的代理对象来实现。

function WillDeclaredVar(variableName)
    local proxy = { environment = _ENV or _G, variableName = variableName }
    return setmetatable(proxy, {
        __tostring = function(proxy)
            return proxy.environment[proxy.variableName]
        end
    })
end

-- a will compute a value based on the current value of b when needed
a = WillDeclaredVar('b')
sheepCount = 123
b = sheepCount
print(a)

输出:

123

【讨论】:

  • 感谢您的帮助。我虽然在 XY 问题中。您能用新添加的代码查看我的问题吗?
  • 只使用表会更容易也更便宜:/ 闭包需要一些堆栈空间和调用资源。
【解决方案2】:

要使var1 成为var2 的引用,请写var1 = ReferenceF or var2(请注意“ReferenceFor”中的空格!)

do
   local values, references, reference_flag = {}, {}
   setmetatable(_G, {
      __index = function (_, name)
         if name == 'ReferenceF' then
            reference_flag = true
         elseif reference_flag then
            reference_flag = false
            return {[references] = name}
         elseif references[name] then
            return _G[references[name]]
         else
            return values[name]
         end
      end,
      __newindex = function (_, name, val)
         if type(val) == 'table' and val[references] then
            references[name] = val[references]
         else
            values[name] = val
         end
      end
   })
end

a = ReferenceF or b  -- a is Reference For b
b = ReferenceF or c  -- b is Reference For c
sheepCount = 123
c = sheepCount
print(a, b, c)  --> 123 123 123

【讨论】:

  • 哦...谢谢!这是完美的!甚至我的问题也很愚蠢,我不知道为什么在 TeP(github.com/phu54321/TrigEditPlus) o>-
  • 我不喜欢这个答案,因为使用了全局变量并覆盖了环境的元表。这既不安全也不利于性能。
  • @Youka - “使用全局变量”是作者的要求。但是这个解决方案可以很容易地适应在其他表中使用变量而不是_G。关于安全性:一般来说,这个解决方案是不安全的,因为忽略了_G 的先前元表。但是作者使用的系统似乎没有为_G使用metatable,所以在这种特殊情况下是安全的。关于性能:是的,使用全局代理表对性能有一些影响。虽然不是特别高:作者使用的脚本子系统不是其宿主应用程序的瓶颈,所以不用担心,开心
  • 已确认。我想我需要再问一个问题并提供更详细的解释。顺便说一句,您认为您可以解决实际代码的问题吗?我对 Lua 了解不多,但我有一些想法。在我看来,如果使用自己的文件读取功能(我的意思是 lua 脚本文件),我想我可以计算调用函数“触发器”的次数,然后我可以得到将定义的变量函数'portal()'事先。
  • 我的意思是......类似于:io.open(file, its own) THEN find.string("Trigger", ...) THEN if find the string "Portal" then... ( ...) ...我希望你明白我在说什么
猜你喜欢
  • 1970-01-01
  • 2021-07-04
  • 1970-01-01
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 2011-01-22
  • 2017-05-18
  • 2017-07-05
相关资源
最近更新 更多