所以,如果我有这个lua函数
function dostuff(x)
function foo () x=x+1; end
foo();
return x;
end
事实证明我需要foo很多次。但它主要是有用的,因为它可以访问x upvalue。有没有办法把foo拉出dostuff,但仍然可以访问x?
我尝试将foo()全局并添加到dostuff,如下所示:
function foo () x=x+1; end
function dostuff(x)
foo();
return x;
end
dostuff.foo = foo
这在lua函数中不起作用与表不同(与js不同)。 我仍然觉得这在lua中起作用,可能使用metatables。但我还不太了解它。我知道很多方法可以避免这种情况并解决它。如果有办法,我只是很好奇。
也许另一种方法是,你可以选择闭包来调用全局函数吗?
答案 0 :(得分:3)
更清晰,更清晰的方法是将参数传递给foo
,我建议这样做。
另一种方法是使用全局变量或某些块(即模块或块)本地的变量,这些变量对所有相关函数都是通用的。
否则,我没有找到任何办法。我建议你重新设计你的方法。
答案 1 :(得分:1)
你想要的是dynamic scoping。不幸的是,Lua没有动态范围。它有词汇范围。在JavaScript中,您可以simulate dynamic scoping using eval
,但Lua没有eval
。
作为最后的手段,您可以使用继承。我通常在Lua中继承的方式是使用extend
函数,它类似于JavaScript中的Object.create
函数:
local o = {}
function o:extend(table)
return setmetatable(table, {
__index = self
})
end
使用此方法,我现在可以创建一个将用于动态范围的对象:
local dynamic = o:extend {}
function dynamic:foo()
self.x = self.x + 1
end
方法foo
是动态的,因为它的变量x
不指向任何特定值。这取决于可以更改的self
的值。我们按如下方式使用它:
function dostuff(x)
local scope = dynamic:extend {
x = x
}
scope:foo()
return scope.x
end
但是,每次执行scope
时,最好只执行以下操作,而不是创建新的dostuff
:
local myscope = dynamic:extend {}
function myscope:dostuff(x)
self.x = x
self:foo()
return self.x
end
事实上,如果您决定重构您的代码,如上所示,那么您甚至不需要继承。您所需要做的就是:
local myscope = {}
function myscope:foo()
self.x = self.x + 1
end
function myscope:dostuff(x)
self.x = x
self:foo()
return self.x
end
唯一的区别是,现在您必须致电myscope:dostuff
而不是直接致电dostuff
。然而,这是一件好事,因为您不会污染全球范围。
这就是我这样做的方式,这也是我建议您这样做的方式。所有Lua标准库函数也在对象上定义。
答案 2 :(得分:0)
由于您只给出了您想要做的粗略示例,而不是您的实际用例,因此建议替代方案有点困难。首先,对我来说,这就像你想要的那样
local x;
function foo() x=x+1 end
function dostuff(a)
x = a;
foo();
return x;
end
我的问题是foo
非常简单,绝对没有理由不使它成为一个值x
并返回x+1
的函数。此外,虽然x的必要初始化步骤并不是很糟糕,并且不应该立即导致任何错误,但是当你必须记住为另一个函数初始化变量时,将使开发变得有点奇怪。如果不这样做,就创建一个调试地狱。
所以,既然Lua也支持多个返回值,那么上面的代码实际上是一个坏主意,它不会给你带来任何好处:
function foo(a,b,c) return a,b,c end
function dostuff()
a,b,c = foo(a,b,c);
end
由于你写了关于代码重用的内容,这里有一个... nudge 你可以做什么,它正在利用闭包。
你可以改变你的结构,不要把x
作为参数,但要dostuff
取foo
作为参数:
function dostuff(foo)
return foo()
end
dostuff(function() return 1 end)
dostuff(function() return 2 end)
进一步向您介绍一种名为partial application的技术。
function dostuff(foo)
return function(x)
return foo(x);
end
end
dostuff(function(x) return x+1 end)(17)
local f = dostuff(function(x) return x+1 end)
f(17)f(18)f(19) -- ...
现在这意味着您不仅可以从外部修改函数的工作方式,还可以保存该状态。作为额外的奖励,您还可以在外部功能中进行昂贵的操作,每个“实例”只需执行一次操作,并节省一些性能。
我希望这些都足以帮助您解决代码重用问题;)