LÖVE (Love2D) LuaJIT言語編:4.変数と式

(2018.7.14. 公開)

4-1. 変数

 「変数」は、値を格納できる箱のようなものである。他のプログラム言語では、格納できる値の型が変数ごとに決められている場合があるが、Lua/LuaJIT では、1つの変数にどのような型の値も格納することができる。

 通常の変数は、2-1.で示した「名前」をつけて表す。名前 = 式 という記述がプログラム中に現れると、「名前」で表される変数に「式」で表される値が格納される。(「式」については、すぐあとで説明する。)「名前」で表される変数がまだ一度も使われていない場合は、新しい変数がその「名前」で作られる。変数に値を格納することを「代入する」と呼ぶ。

  a = 1     -- 変数 a に値 1 を代入する
  b = "abc" -- 変数 b に文字列 "abc" を代入する

 名前で表される変数とは別に、テーブルのフィールドも変数と同じように使うことができる。前ページと同様に、下のようなテーブルがあるとしよう。

キー 1 2 3 "dog" "cat"
フィールド (値1) (値2) (値3) (値4) (値5)

 このテーブルが t という変数に入っているものとする。このとき、テーブルのフィールドは、下のように角カッコ [ ] を使って記述する。

  t[1]  -- (値1)
  t[2]  -- (値2)
  t[3]  -- (値3)
  t["dog"] -- (値4)
  t["cat"] -- (値5)

 上の "dog", "cat" のように、角カッコの中が文字列定数で、Lua/LuaJIT の名前として有効な文字列である場合は、下のようにピリオド . を使った省略記法が使える。

  t.dog  -- (値4)
  t.cat  -- (値5)

 テーブルを変数に代入する時、テーブルのコピーが作られるわけではない。従って、上のテーブル t を別の変数に代入すると、2つの変数は同じテーブルを指すことになる。下のように、ややこしいことになる場合もあるので、注意しておくこと。

  s = t        -- s と t は同じテーブルを指す
  t[2] = 15    -- t[2] に値を入れた
  s[2] = 10    -- s[2] に別の値を入れた:実は t[2] と s[2] は同じフィールド
  print(t[2])  -- 10 が表示される(15 ではない)

注:print は、引数を表示するための Lua/LuaJIT の組み込み関数だが、LÖVE のプログラム中に書いても、LÖVE の画面上には表示されない。LÖVE のプログラム中で print を使いたい場合は、コンソールまたはターミナルから LÖVE を起動する必要がある。

4-2. 式

 「式」は、値に何らかの操作を行って、新しい値を得るものである。「何らかの操作」を表す字句を「演算子」と呼ぶ。数学でなじみ深い「足し算」「掛け算」などの式は、それぞれ +, * などの演算子で表される。Lua/LuaJIT の演算子には、次のようなものがある。

4-2-1. 算術演算子

 数値に働きかけて、新しい数値を与えるものである。両側の値は、必要ならば数値に変換される。

  a + b  -- a と b を足す
  a - b  -- a から b を引く
  a * b  -- a と b をかける
  a / b  -- a を b で割る
  a % b  -- a を b で割った余り
  a ^ b  -- a の b 乗
  -a     -- a の符号を反転したもの

4-2-2. 連結演算子

 2つの文字列を連結して、新しい文字列を作るものである。両側の値は、必要ならば文字列に変換される。

  s .. t  -- s と t を連結する

4-2-3. 関係演算子

 2つの値の関係を調べて、結果を true(真)または false(偽)で示す。

  a == b  -- a と b は等しいか?
  a ~= b  -- a と b は等しくないか?
  a < b   -- a は b より小さいか?
  a > b   -- a は b より大きいか?
  a <= b  -- a は b より小さいかまたは等しいか?
  a >= b  -- a は b より大きいかまたは等しいか?

 ==, ~= では、型の変換は行われない。例えば、0 == "0"false となる。左辺は数値、右辺は文字列で、型が異なるためである。

 大小関係を調べる演算子の働きは、両側の値の型によって異なる。両側の値が数値ならば、通常の大小関係となる。両側の値が文字列ならば、文字コードの数値を先頭から比較して、大きい数値が先に現れた方が大きいと解釈する。

4-2-4. 論理演算子

 次の3つの論理演算子がある。

  not a    -- a でない
  a and b  -- a かつ b
  a or b   -- a または b

 これらの式は、下のような結果を与える。

aの値 bの値 結果
not a nilまたはfalse --- true
それ以外 --- false
a and b nilまたはfalse 評価しない aの値
それ以外 何であっても bの値
a or b nilまたはfalse 何であっても bの値
それ以外 評価しない aの値

 and, or には、顕著な特徴がある。それは、これらの演算子が「結果がわかっているときは、2つ目の値を計算しない」ことである。a and b について言えば、a が「偽」であれば、b が何であっても結果は「偽」となる。このような場合、b は計算されない。例えば、x > 10 and x < 20 を求めるとき、仮に x が 8 であったとすると、x > 10 が偽なので、and の右側の結果に関わらず、この式の結果は「偽」となる。この場合、x20 との比較は行われない。このように、結果がわかった時点でそれ以降の計算を行わないことを「短絡評価」と呼ぶ。Lua/LuaJIT では、andor のみが短絡評価を行う。

 上の例の場合では、x < 20 の比較を行うかどうかは重大な違いをもたらさないが、2つ目の値が非常に時間のかかる処理であったり、副作用を伴う関数の呼び出し(関数については後述する)だったりする場合は、実行されるかどうかで重要な違いが生まれる。

 and, or についてのもう一つの特徴は、これらの演算子が返すのが true または false とは限らず、「演算子の両側の値のうち一方」だという点である。結果を truefalse==~= で比較したりすると、思っていたのと違う結果になることがあるので、注意を要する。

4-2-5. 長さ演算子

 # を式の前に置くと、その式の値の「長さ」が得られる。値が文字列の時は、バイト数が得られる。値が数値の時は、エラーになる。

 値がテーブルの場合は、「1から N までの連続した整数のキー」を持つ時、そのテーブルの「長さ」は N となる。途中で値が抜けているとき(たとえば t = { "dog", "cat", nil, "cow" } だと、t[3] が抜けている)は、# でテーブルの「長さ」を正しく求めることはできない。また、正の整数値でないキーが存在しても、「長さ」には影響を与えない。例えば、t = { "dog", "cat", a = "cow" } の場合、#t は2となる。

4-2-6. 優先順位

 数学では、掛け算・割り算が足し算・引き算よりも優先する。Lua/LuaJIT でも同様に、演算子 *, / は 演算子 +, - よりも優先順位が高い。他の演算子についても優先順位が決められている。それは下の通りである。

優先順位   演算子
    1      ^
    2      not  #    -(マイナス符号)
    3      *    /    %
    4      +    -
    5      ..
    6      <    >    <=   >=   ~=   ==
    7      and
    8      or

4-3. 関数呼び出し

 「関数」については、「値と型」のところで説明した。関数を呼び出すには、下のような形式を使う。funcname は関数とする。

  funcname()  -- 引数なし
  funcname(arg1) -- 引数1つ
  funcname(arg1, arg2)  -- 引数2つ

 引数が文字列定数1つだけの場合は、カッコを省略することが許される。

  funcname"文字列"    -- 下の式と同じ
  funcname("文字列")

 式の中で関数呼び出しを用いた場合、関数の戻り値が式の値となる。

 関数呼び出しには、コロン : を使った次のような形式もある。この形式を、「メソッド呼び出し」と言う。

  t:name(arg1, arg2)  -- 引数はいくつでもよい(この例では2つ)

 上のメソッド呼び出しは、下の関数呼び出しと等価である。つまり、コロンの前の式が「暗黙の第1引数」となる。

  t.name(t, arg1, arg2)  -- t が暗黙の第1引数

 「空白文字」の項でも書いた通り、関数名と引数リストの間に改行を入れてはならない。

  print(x, y)  -- x, y を表示する
  print
  (x, y)  -- こう書いてはいけない

4-4. テーブル初期化式

 テーブル初期化式は、新しいテーブルを作成する式である。下のように記述する。

  {}  -- 空のテーブル
  { "value1", "value2", "value3" } -- 1から始まる整数をキーとして使う
  { cat = "value1", dog = "value2" } -- "cat", "dog" をキーとして使う
  { ["ca" .. "t"] = "value1", ["d" .. "og"] = "value2" }
    -- キーが式で表される場合は、その式を角カッコで囲む

目次