Зачем использовать блок do-end в Lua?

Я продолжаю пытаться найти ответы на это, но не могу этого сделать. Я хотел знать, для чего на самом деле используется блок do-end? Он просто говорит, что значения используются, когда это необходимо в моей книге, так как я могу использовать это?

использую ли я его для уменьшения области локальных переменных, помещая функцию в цикл do-end и помещая локальные переменные вне функции, но внутри этого блока do-end, и переменные будут видны функции? Но тогда функция все еще может быть звонил?

извините за очень расплывчато. Надеюсь, в этом есть смысл. Возможно, иллюстрированный пример может быть полезен ^^

3 ответов


блоки do-end имеют отношение к проблеме переменной области видимости. По сути, когда вы используете идентификатор, какое значение он имеет? Например, какие номера будут напечатаны, когда мы напишем следующую программу?

local x = 10
if x > 0 then
    local x = 17
    print(x)
end
print(x)

когда дело доходит до локальных переменных, Lua использует стандартный лексический охват, как хорошо объясняется в 4.2 программирования в книге Lua. Лексический объем очень полезен по нескольким причинам:

  • в переменная область видимости статична. Вы знаете, просто глядя на исходный код, какие переменные и функции соответствуют каждому идентификатору в вашем коде. Это противоречит динамической области, которую вы найдете в Bash или косвенной диспетчеризации с помощью вызовов методов или поиска массива, где вам нужно подумать о потоке выполнения программы, чтобы узнать, какое значение вы получите.

  • переменная область видимости ограничена, что помогает читаемости и позволяет избежать некоторых Багз:

    • если вы объявляете переменную только тогда, когда вам нужно будет ее использовать, вы можете объявить ее и инициализировать одновременно. С другой стороны, если вы объявите все переменные в верхней части функции, вы можете случайно использовать их перед инициализацией.

    • если вы определяете переменную внутри внутренней области, вы не можете случайно использовать ее во внешней масштабы.

  • лексический охват позволяет некоторые очень выразительные идиомы когда вы объединяете его с вложенными функциями (замыканиями).

обычно вам не нужно беспокоиться об указании областей переменных самостоятельно. Функции, циклы и условные обозначения автоматически вводят новые области, и этого обычно достаточно для предоставления вашим переменным хорошо ограниченной области. Тем не менее, время от времени вы можете хотите ввести дополнительные области из воздуха, и мы можем использовать do-end для этого. Программирование 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)"

тем не менее, do-end не нужно использовать так часто. Если блок кода небольшой, то меньше необходимости скрывать локальные переменные, и если блок кода большой, часто лучше поместить блок кода в собственную подпрограмму. Время, когда я нахожу, что do-end сияет, когда вам нужно только выполнить вычисление один раз - функции потенциально могут быть вызваны много раз, но если вы используете блок do-end, вы ясно даете понять, что вы только запускаете этот кусок кода один раз.


да do end блок может использоваться для ограничения области переменных; чтобы сохранить функцию, которая использует эти переменные видимыми, у вас есть несколько опций

  1. локализовать переменную, которая удерживает функцию вне блока:

    local func    
    do
      local a = 0
      func = function(inc)
        a = a + inc
        return a
      end
    end
    
  2. использовать глобальную функцию:

    do
      local a = 0
      function func(inc)
        a = a + inc
        return a
      end
    end
    
  3. использовать метод:

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

во всех трех случаях вы все еще можете позвонить func() после блока закрыто, но a только видимого из этой функции и нигде больше.


в дополнение к хорошим ответам, уже данным, я хочу упомянуть возможность поделиться частной переменной среди двух или более функций:

do

  local i = 0

  function inc()
    i = i + 1
    return i
  end

  function dec()
    i = i - 1
    return i
  end

end