(2018.7.14. 公開)
「変数」は、値を格納できる箱のようなものである。他のプログラム言語では、格納できる値の型が変数ごとに決められている場合があるが、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 を起動する必要がある。
「式」は、値に何らかの操作を行って、新しい値を得るものである。「何らかの操作」を表す字句を「演算子」と呼ぶ。数学でなじみ深い「足し算」「掛け算」などの式は、それぞれ +
, *
などの演算子で表される。Lua/LuaJIT の演算子には、次のようなものがある。
数値に働きかけて、新しい数値を与えるものである。両側の値は、必要ならば数値に変換される。
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 の符号を反転したもの
2つの文字列を連結して、新しい文字列を作るものである。両側の値は、必要ならば文字列に変換される。
s .. t -- s と t を連結する
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
となる。左辺は数値、右辺は文字列で、型が異なるためである。
大小関係を調べる演算子の働きは、両側の値の型によって異なる。両側の値が数値ならば、通常の大小関係となる。両側の値が文字列ならば、文字コードの数値を先頭から比較して、大きい数値が先に現れた方が大きいと解釈する。
次の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
の右側の結果に関わらず、この式の結果は「偽」となる。この場合、x
と 20
との比較は行われない。このように、結果がわかった時点でそれ以降の計算を行わないことを「短絡評価」と呼ぶ。Lua/LuaJIT では、and
と or
のみが短絡評価を行う。
上の例の場合では、x < 20
の比較を行うかどうかは重大な違いをもたらさないが、2つ目の値が非常に時間のかかる処理であったり、副作用を伴う関数の呼び出し(関数については後述する)だったりする場合は、実行されるかどうかで重要な違いが生まれる。
and
, or
についてのもう一つの特徴は、これらの演算子が返すのが true
または false
とは限らず、「演算子の両側の値のうち一方」だという点である。結果を true
や false
と ==
や ~=
で比較したりすると、思っていたのと違う結果になることがあるので、注意を要する。
#
を式の前に置くと、その式の値の「長さ」が得られる。値が文字列の時は、バイト数が得られる。値が数値の時は、エラーになる。
値がテーブルの場合は、「1から N までの連続した整数のキー」を持つ時、そのテーブルの「長さ」は N となる。途中で値が抜けているとき(たとえば t = { "dog", "cat", nil, "cow" }
だと、t[3]
が抜けている)は、#
でテーブルの「長さ」を正しく求めることはできない。また、正の整数値でないキーが存在しても、「長さ」には影響を与えない。例えば、t = { "dog", "cat", a = "cow" }
の場合、#t
は2となる。
数学では、掛け算・割り算が足し算・引き算よりも優先する。Lua/LuaJIT でも同様に、演算子 *
, /
は 演算子 +
, -
よりも優先順位が高い。他の演算子についても優先順位が決められている。それは下の通りである。
優先順位 演算子
1 ^
2 not # -(マイナス符号)
3 * / %
4 + -
5 ..
6 < > <= >= ~= ==
7 and
8 or
「関数」については、「値と型」のところで説明した。関数を呼び出すには、下のような形式を使う。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) -- こう書いてはいけない
テーブル初期化式は、新しいテーブルを作成する式である。下のように記述する。
{} -- 空のテーブル
{ "value1", "value2", "value3" } -- 1から始まる整数をキーとして使う
{ cat = "value1", dog = "value2" } -- "cat", "dog" をキーとして使う
{ ["ca" .. "t"] = "value1", ["d" .. "og"] = "value2" }
-- キーが式で表される場合は、その式を角カッコで囲む
目次