web-dev-qa-db-ja.com

Luaでdo-endブロックを使用するのはなぜですか?

私はこれに対する答えを見つけようとし続けますが、そうすることができません。知りたかったのですが、実際に使用されているdo-endブロックは何ですか?私の本で必要なときに値が使用されると書かれているだけなので、これをどのように使用できますか?

関数をdo-endループに配置し、ローカル変数を関数の外側、ただしこのdo-endブロック内に配置することで、ローカル変数のスコープを縮小するために使用しますか?変数は関数によって認識されますか?しかし、それでも関数を呼び出すことはできますか?

あいまいでごめんなさい。それが理にかなっていることを願っています。たぶん、図解された例が役に立つかもしれません^^

17
Mayron

Do-endブロックは、変数スコープの問題と関係があります。基本的に、識別子を使用する場合、どのような値がありますか?たとえば、次のプログラムを作成すると、どのような数字が出力されますか?

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

ローカル変数に関しては、Luaは標準の字句スコープを使用します。これはLuaのプログラミングの本の セクション4.2 で詳しく説明されています。字句スコープは、いくつかの理由で非常に役立ちます。

  • 変数のスコープは静的です。ソースコードを見るだけで、コード内の各識別子に対応する変数と関数がわかります。これは、Bashで見られる動的スコープや、メソッド呼び出しや配列ルックアップを介した間接ディスパッチとは対照的です。この場合、プログラムの実行フローを考慮して、最終的にどの値になるかを知る必要があります。

  • 変数のスコープは制限されているため、読みやすくなり、いくつかのバグを回避できます。

    • 変数を使用する必要がある場合にのみ変数を宣言する場合は、変数の宣言と初期化を同時に行うことができます。一方、関数の先頭ですべての変数を宣言すると、初期化する前に誤って変数を使用してしまう可能性があります。

    • 内側のスコープ内で変数を定義した場合、それを誤って外側のスコープで使用することはできません。

  • 字句スコープは、ネストされた関数(クロージャ)と組み合わせると、いくつかの 非常に表現力豊かなイディオム を有効にします。

通常、変数スコープを自分で指定することを心配する必要はありません。関数、ループ、および条件は自動的に新しいスコープを導入し、通常は変数に十分に制約されたスコープを与えるのに十分です。とは言うものの、たまに、薄い空気からいくつかの追加のスコープを導入したい場合があり、そのためにdo-endを使用できます。プログラミングLuaには、2次方程式の解を計算する次の例があり、計算にはいくつかの一時的なものがあります。

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ブロックがない場合、a2dは、不要になった後で誤って使用される可能性があります。

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が輝いているのは、計算を1回だけ実行する必要があるときです。関数は何度も呼び出される可能性がありますが、do-endブロックを使用すると、そのコードのみを実行していることが明確になります。一度。

19
hugomg

はい、_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
    _

3つのケースすべてで、ブロックが閉じられた後でもfunc()を呼び出すことができますが、aはその関数からのみ visible であり、他の場所ではありません。

11
Paul Kulchenko

すでに与えられた良い答えに加えて、2つ以上の関数間でプライベート変数を共有する機能について言及したいと思います。

do

  local i = 0

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

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

end
9
Niccolo M.