2

所以如果我有这个lua函数

function dostuff(x) 
   function foo () x=x+1; end
   foo(); 
   return x; 
end

事实证明我需要 foo 很多次。但它主要是有用的,因为它可以访问 x 上值。有没有办法将 foo 从 dostuff 中拉出来,但仍然可以访问 x?

我尝试将 foo() 全局化并将其添加到 dostuff,如下所示:

function foo () x=x+1; end
function dostuff(x) 
   foo(); 
   return x; 
end
dostuff.foo = foo

这在 lua 中不起作用,函数与表不同(与 js 不同)。我仍然觉得这在 lua 中确实有效,可能使用元表。但我只是对此还不够了解。我知道很多方法可以避免这种情况并解决它。我只是好奇是否有办法做到这一点。

也许另一种看待方式是,您可以选择闭包来调用全局函数吗?

4

3 回答 3

3

一种更清晰,更清晰的方法是将参数传递给foo,我会推荐。

另一种方法是使用全局变量,或某些块(即模块或块)的局部变量,这些变量对所有相关函数都是通用的。

否则,我没有找到任何方法来做到这一点。我建议重新设计你的方法。

于 2013-06-18T06:15:56.453 回答
1

你想要的是动态范围。不幸的是 Lua 没有动态作用域。它具有词法作用域。在 JavaScript 中,您可以使用 模拟动态范围eval,但 Lua 没有eval.

作为最后的手段,您可以使用继承。我通常在 Lua 中做继承的方式是使用extend函数,类似于Object.createJavaScript 中的函数:

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 标准库函数也是在对象上定义的。

于 2013-06-20T02:44:22.587 回答
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

既然你写了关于代码重用的文章,这里是一个一般性的......推动你可以做的其他事情,那就是使用闭包。

你可以改变你的结构,不把 foox作为参数,而是把dostufftakefoo作为参数:

function dostuff(foo)
    return foo()
end
dostuff(function() return 1 end)
dostuff(function() return 2 end)

更进一步,您将了解一种称为部分应用的技术。

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

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

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

于 2013-06-20T00:51:36.770 回答