我可以将函数注入Lua函数吗?

时间:2013-06-18 04:41:34

标签: lua

所以,如果我有这个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。但我还不太了解它。我知道很多方法可以避免这种情况并解决它。如果有办法,我只是很好奇。

也许另一种方法是,你可以选择闭包来调用全局函数吗?

3 个答案:

答案 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作为参数,但要dostufffoo作为参数:

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) -- ...

现在这意味着您不仅可以从外部修改函数的工作方式,还可以保存该状态。作为额外的奖励,您还可以在外部功能中进行昂贵的操作,每个“实例”只需执行一次操作,并节省一些性能。

我希望这些都足以帮助您解决代码重用问题;)