为什么在Lua中使用do结束块?

为什么在Lua中使用do结束块?,lua,block,scoping,Lua,Block,Scoping,我一直试图找到答案,但没有找到。我想知道,do end block实际上是用来做什么的?它只是说在我的书中需要时使用值,那么我如何使用它呢 我是否使用它来减少局部变量的范围,方法是将函数放在Do end循环中,并将局部变量放在函数外部,但放在Do end块中,函数将看到这些变量?但是这个函数还能被调用吗 抱歉说得太含糊了。我希望这是有道理的。也许举例说明可能有用^^是的,do end块可用于限制变量的范围;要使使用这些变量的函数保持可见,您有几个选项 本地化将函数保持在块之外的变量: local

我一直试图找到答案,但没有找到。我想知道,do end block实际上是用来做什么的?它只是说在我的书中需要时使用值,那么我如何使用它呢

我是否使用它来减少局部变量的范围,方法是将函数放在Do end循环中,并将局部变量放在函数外部,但放在Do end块中,函数将看到这些变量?但是这个函数还能被调用吗


抱歉说得太含糊了。我希望这是有道理的。也许举例说明可能有用^^

是的,
do end
块可用于限制变量的范围;要使使用这些变量的函数保持可见,您有几个选项

  • 本地化将函数保持在块之外的变量:

    local func    
    do
      local a = 0
      func = function(inc)
        a = a + inc
        return a
      end
    end
    
  • 使用全局函数:

    do
      local a = 0
      function func(inc)
        a = a + inc
        return a
      end
    end
    
  • 使用以下方法:

    local tbl = {}
    do
      local a = 0
      function tbl:func(inc)
        a = a + inc
        return a
      end
    end
    

  • 在这三种情况下,在块关闭后,您仍然可以调用
    func()
    ,但
    a
    仅来自该函数,而不是其他任何地方。

    do结束块与变量范围问题有关。本质上,当您使用标识符时,它有什么值?例如,当我们编写以下程序时,将打印哪些数字

    local x = 10
    if x > 0 then
        local x = 17
        print(x)
    end
    print(x)
    
    当谈到局部变量时,Lua使用标准的词法作用域,这在Lua书中的编程部分中有很好的解释。词法范围非常有用,原因如下:

    • 变量作用域是静态的。通过查看源代码,您就知道哪些变量和函数对应于代码中的每个标识符。这与Bash中的动态作用域相反,或者通过方法调用或数组查找进行间接调度,在这里,您需要考虑程序的执行流,以知道最终会得到什么值

    • 变量范围有限,这有助于提高可读性并避免一些错误:

      • 如果只在需要使用变量时才声明变量,则可以同时声明和初始化它。另一方面,如果在函数顶部声明所有变量,那么在初始化之前可能会意外地使用一个变量

      • 如果在内部作用域中定义变量,则不能意外地在外部作用域中使用它

    • 当您将词法作用域与嵌套函数(闭包)结合使用时,它会启用一些功能

    通常,您不需要担心自己指定变量作用域。函数、循环和条件会自动引入新的作用域,这通常足以为变量提供一个约束良好的作用域。这就是说,每隔一段时间,你可能会想引进一些额外的范围出稀薄的空气,我们可以使用做结束。编程Lua有以下示例,其中您希望计算二次方程的解,并且计算有一些临时性:

    do
      local a2 = 2*a
      local d = sqrt(b^2 - 4*a*c)
      x1 = (-b + d)/a2
      x2 = (-b - d)/a2
    end          -- scope of `a2' and `d' ends here
    print(x1, x2)
    
    如果没有do end块,
    a2
    d
    可能会在不再需要它们后被意外使用:

    local a2 = 2*a
    local d = sqrt(b^2 - 4*a*c)
    x1 = (-b + d)/a2
    x2 = (-b - d)/a2
    print(x1, x2)
    
    print(a2) -- OOPS! I wanted to say "print(a)"
    

    也就是说,doend不需要经常使用。如果代码块较小,则不需要隐藏局部变量,如果代码块较大,则将代码块放入其自身的子例程中通常是更好的方法。我发现do end非常出色的时候,你只需要做一次计算——函数可能会被调用很多次,但如果你使用do end块,你会清楚地表明你只运行了一次代码。

    除了已经给出的好答案,我想提及在两个或多个函数之间共享私有变量的能力:

    do
    
      local i = 0
    
      function inc()
        i = i + 1
        return i
      end
    
      function dec()
        i = i - 1
        return i
      end
    
    end