默认值和变量作用域

我觉得我在 Lua 中关于变量作用域和默认值的问题被忽略了一些东西。考虑以下函数:

function printtable(x, indentation_level)

   indentation_level = indentation_level or 0

   function indent()
      dent = ''
      for i=1,indentation_level do
         dent = dent..'__'
      end
      return dent
  end

   if type(x) ~= 'table' then
      return tostring(x)
   end

   rpr = ''
   for k, v in pairs(x) do
      rpr = rpr..indent()..'['..printtable(k)..']'..' = '..printtable(v, indentation_level+1)
   end
   return rpr
end

当我用以下方式调用它时:

t = {1,2,3}

print(printtable(t))

我会得到[1] = 1__[2] = 2__[3] = 3

我预期的是[1] = 1[2] = 2[3] = 3

我在 Python 中重写了这个函数,以查看我的逻辑错误在哪里:

def printdict(x, indentation_level=0):

    def indent():

        dent = ''
        for i in range(indentation_level):
            dent += '__'
        return dent

    if type(x) != dict:
        return str(x)

    rpr = ''
    for k, v in x.items():
        rpr = rpr+indent()+'['+printdict(k)+'] = '+printdict(v, indentation_level+1)

    return rpr

当我用以下方式调用它时:

t = {1:1,2:2,3:3}

print(printdict(t))

我得到了我期望的结果:[1] = 1[2] = 2[3] = 3

那么,Lua 版本出了什么问题?我对变量作用域或其他机制缺少了什么?

点赞
用户2226988
用户2226988

在Lua中,变量“默认为全局”。如果在变量使用上面没有本地变量(包括参数),它将绑定到全局环境上。如果有,它将绑定到最接近的上方变量。

2018-02-09 18:04:29
用户3574628
用户3574628

首先,您应该将indentdentrpr以及可能是printtable声明为local。(与Python不同,Lua要求我们声明变量以指定其作用域。参数和循环变量会自动成为定义它们的块的本地变量。)

问题是由于indent是全局变量导致的。

请注意,indentation_level是局部变量,因为它是一个参数。indent引用了indentation_level,这意味着indent是一个闭包。闭包是存储对外部局部变量引用的函数。

每次调用printtable,它都会定义一个具有当时正在运行作用域中的indentation_level的新的indent实例。在您的代码中,indent是全局变量,因此每个新定义的indent都会覆盖先前的。

在这个循环中:

for k, v in pairs(x) do
  rpr = rpr..indent()..'['..printtable(k)..']'..' = '..printtable(v, indentation_level+1)
end

...您调用了printtable,它会将indent定义为一个具有indentation_level为1的变量。这就是在第一次迭代之后每次迭代中调用的indent

请注意,您的输入表格没有子表格,因此递归仅到第一级。该循环只在初始调用中运行。这就是为什么indentation_level永远不会超过1(对于您试图做的事情是有意义的)。

您可以通过使indent成为local来解决此问题。

2018-02-10 04:11:10