←前
目次
次→

Luaスクリプト機能

$Date: 2012/04/10 03:20:36 $

Lua言語の文法

ここで、Lua言語の文法で、よく使う範囲について簡単にまとめておきます。

それぞれの書式の中で、点線で囲まれた部分は省略可能であることを示します。

値と型

Lua言語で扱うことのできる値には、すべて型があります。Lua言語での型には以下のものがあります。

数値型

数値型は、内部的に32ビット符号付整数で表されるものと、桁数に制限のない符号付整数であらわされるものがあり、前者をFIXNUM、後者をBIGNUMと呼びます。FIXNUMとBIGNUMの違いは、表現できる数の範囲だけですが、多くのライブラリ関数では数値型の引数としてFIXNUMしか受け付けられません。

以降では、FIXNUMとBIGNUMを総称するときは「数値型」「数値」、FIXNUMだけを表す場合は「数値型(FIXNUM)」「FIXNUM」、BIGNUMだけを表す場合は「数値型(BIGNUM)」「BIGNUM」と表記します。また、BIGNUMは_RT_LUA_VERSIONが"1.01"以降のファームウェアで扱うことができます。_RT_LUA_VERSIONが"1.0"のファームウェアで扱うことのできる数値はFIXNUMのみです。

数値型の値を直接スクリプト中に書くときには、10進数、あるいは先頭が0xで始まる16進数として書くことができます。また、負の数を表すためには先頭にマイナス(-)を書きます。

一方、先頭にプラス(+)を書くことはできません。プラス(+)は足し算を表す記号としてしか使えません。

オリジナルのLua言語では数値型は浮動小数点数になっていますが、ヤマハルーターへの組み込みでは、整数だけを扱うように変更しています。
数値型(BIGNUM)で扱える数値の桁数は、Luaスクリプト機能が利用できるルーターのメモリサイズによってのみ制限されます。桁数が大きな数値を扱うときにはメモリやCPUを多く使用しますので、あまり大きな桁数の数値は扱わないようにするのが無難です。64ビット整数(20桁)程度の数値であればまったく問題なく扱えます。

文字列型

文字列型は、文字の列を表します。文字列型の値をスクリプト中に書くときには、引用符で囲みます。引用符には以下のものが使えます。

それぞれ、同じ引用符で文字列の両端を囲みます。文字列中に以下のような記述をすれば、文字列に特殊文字を含むことができます。

改行の直前に¥を置くことでも、文字列に改行を含ませることができます。

ヤマハルーターでは、文字の内部コードとしてASCIIおよびShift-JISを使用しています。
ヤマハルーターのコマンドが出力する文字列では、改行は"¥r¥n"の2文字で表されます。一方、コマンドのパラメーターの中に改行を含ませたい場合は、"¥n"1文字、"¥r¥n"2文字のどちらでも構いません。"¥r"1文字だけでは改行とはみなされません。

また、文字列はロングカッコで囲んだ長い形式も使用できます。ロングカッコとは、角カッコ([])2個の間に、0個以上のイコール(=)を置いたもので、イコールの数がN個のものを「レベルNのロングカッコ」と呼びます。以下は、ロングカッコの例です。

長い形式の文字列は、同じレベルの開きロングカッコから閉じロングカッコまでが文字列となります。長い形式の文字列では、ダブルクォートやシングルクォートを使った形式の文字列とは違い、改行を特別なエスケープを必要とせず含むことができます。ただし、開きロングカッコの直後の改行は文字列に含まれず、無視されます。

以下の例では、変数aにすべて同じ文字列を代入しています。

a = 'abc¥n123'
a = "abc¥n123"
a = '¥97bc¥n¥04923'
a = [[abc
123]]
a = [==[
abc
123]==]
    

式展開

文字列の直前に$を置くと、文字列中の${}で囲まれた部分を、Luaの式として展開します。

式展開は_RT_LUA_VERSIONが"1.03"以降のファームウェアで扱うことができます。

展開される式は、..tostring()..という形で前後の文字列と連結されます。また、文字列全体もかっこで囲まれた、文字列を結果とする式となります。

..は連結演算子、tostringは文字列変換関数です。

例:

$"私の名前は${name}です。" ==> ("私の名前は"..tostring(name).."です。")

$"x + y = ${x + y}" ==> ("x + y"..tostring(x + y).."")

$[[私は今、${now() - birthday(me)}才です。]] ==> 
	([[私は今、]]..tostring(now() - birthday(me))..[[才です。]])
    

短い形式の文字列(シングルクォートまたはダブルクォートで囲んだ文字列)では、式展開で展開される式の中でも特殊文字の扱いは文字列のほかの部分と変わりません。そのため、文字列の引用符を式中に含む場合は¥'¥"とする必要がありますが、式展開されるときにはそれらは¥がついたままの形で展開されてしまいます。そのため、短い形式の文字列では、展開される式中に引用符を含めることは不可能となっています。その必要がある場合には、長い形式の文字列を使用してください。

$"f(¥"a¥") == ${f(¥"a¥")}" ==> ("f(¥"a¥") == "..tostring(f(¥"a¥")).."") ... エラー

$[[f("a") == ${f("a")}]] ==> ([[f("a") == ]]..tostring(f("a"))..[[]]) ... OK
    

論理型

論理型は、truefalseという二つの値を持つ型です。論理型の値は、比較演算子の結果として利用されます。また、制御文の条件式では、falseが偽として判定されます。

制御文の条件式では、falseと後述するnilのみが偽として判定され、それ以外はすべて真となります。特に、数値の0や空文字列も偽とならず真であることに注意してください。

nil型

nil型は、nilという値を一つだけ持つ型です。nilは、他の値とはすべて異なること、制御文の条件式では偽と判定されることが特徴です。

関数型

関数型は、Lua言語の関数です。Lua言語では、関数も値として変数に代入したり、別の関数の引数として渡したりすることができます。

テーブル型

テーブル型は、Lua言語では唯一の構造型です。他の言語での配列、構造体、リストといったものはLua言語ではすべてテーブル型で表すことができます。

テーブル型は、キーと値の組を複数格納できる型です。キーと値の組のことを、テーブルの要素と呼びます。キーと値はそれぞれLua言語で扱えるすべての型を取ることができます。

テーブルの要素にアクセスするときには、かぎカッコ([])を使います。

式1 [ 式2 ]
    

式1を評価した値がテーブル型になります。通常は、式1はテーブル型の値を格納した変数の名前です。式2は、キーになる値です。

キーが文字列である場合は、ピリオドを使った書き方も可能です。これは書き方が違うだけで、以下の2行はまったく同じテーブル要素を表します。

式1 . 名前
式1 [ "名前" ]
    

テーブル型の値をプログラム中に書くときには、テーブルコンストラクタを用います。テーブルコンストラクタの書式は以下のようなものです。

{
  [式] = 式,
  名前 = 式,
  式
}

「[式] = 式」の書き方の場合、最初の式の値をキーとし、後ろの式の値を格納します。「名前 = 式」の場合は、文字列「"名前"」をキーとします。キーが省略された場合は、先頭から1、2、3…と続く数値をキーとします。

それぞれの初期化部の区切りを表すために、コンマ(,)もしくはセミコロン(;)を置きます。初期化部がまったく省略された場合には、何も要素を持たないテーブルとなります。

配列

テーブルの中でも、すべての要素のキーが1以上の数値型(FIXNUM)であり、かつ、キーが1から最大値まで隙間無く存在するものをこの文書および関連文書の中では配列と呼んでいます。配列はテーブル型の特殊な形ですが、配列にのみ適用可能なライブラリ関数があるなど、通常のテーブル型とは少し異なる扱いをされています。

その他

Lua言語には、その他の型としてユーザーデータ型、スレッド型がありますが、ルーターのLuaスクリプトとしてはあまり使うことがないため、この文書では解説しません。

変数

変数とは、値を保存することのできる場所のことです。変数には、ローカル変数とグローバル変数があります。

ローカル変数は、ローカル変数宣言文で宣言された変数のことです。その変数は、宣言されたブロックでのみ有効です。

グローバル変数は、スクリプト全体で有効な変数です。グローバル変数を宣言する方法はありません。逆に言えば、ローカル変数宣言文で宣言されていない変数はすべてグローバル変数となります。

変数には名前があります。変数の名前には、アルファベット、数字、アンダースコア(_)が使用できますが、先頭は数字以外でなくてはいけません。アルファベットの大文字、小文字は違う文字であると認識されます。また、以下の名前は予約語であり、変数の名前としては使用できません。

and, break, do, else, elseif, end, false, for, function, if, in, local, nil, not, or, repeat, return, then, true, until, while

Lua言語の変数はC言語やBASIC言語の変数とは異なり、代入できる値の型に制限がありません。どのような型の値でも代入することができます。

式は、代入文の左辺や、制御文の条件式、関数定義、関数呼び出しの引数で使われます。式は評価すると何らかの値が得られます。

式は、変数、リテラル(プログラム中に値を直接書いたもの)、関数定義、および、それらに演算子を適用したものとなります。

変数だけの式の値は、変数の値となります。リテラルは、そのものの値です。関数定義の場合は、関数が値となります。

演算子には、以下の種類があります。

算術演算子

算術演算子は、数値同士の算術演算を行います。二項演算子(数値の間に記述し、前後の数値を演算する)と、単項演算子(数値の前に記述し、後ろの数値を演算する)があり、以下の演算子があります。

数値は整数しか扱えないので、除算の結果は商を負の無限大方向へ丸めた値となります。被除数、除数とも正の場合は、商の整数部となります。このあたりは、少数や分数を習う前の小学校の算数を思い出してください。

5割る2は、2あまり1。したがって、5/2 ⇒ 2、5%2 ⇒ 1。

C言語の除算では、整数同士の除算の結果は商を0方向へ丸めた値となります。Lua言語とは丸め方向が違うため、商が負になる場合には結果が異なってきますので注意してください。
Lua : 5 / (-2) ⇒ -3、5 % (-2) ⇒ -1
C : 5 / (-2) ⇒ -2、5 % (-2) ⇒ 1

算術演算子は、通常数値のみに適用されますが、文字列に適用された場合、文字列の見た目が数値である場合に限り、文字列が数値に変換されて演算されます。

5 + "2" ⇒ 7
5 + "a" ⇒ エラー
"5" + "2" ⇒ 7

特に、加算演算子(+)を二つの文字列に適用した場合も、文字列連結ではなく数値の加算として扱われることには注意してください。文字列連結には専用の演算子があります。

比較演算子

比較演算子は、等号、不等号と大小比較があります。比較演算子は演算の結果として論理型のtruefalseを返します。

等号(==)と不等号(‾=)は、前後の式の値が等しいかどうかを判定します。いずれもまず、値の型が一致しているかどうかを調べ、型が一致している場合に限り、値の比較を行います。

等号(==)では、型も値も一致している場合にtrueとなり、そうでない場合はfalseになります。

不等号(‾=)では型が違うか、値が違う場合にtrueとなり、その他の場合はfalseになります。

算術演算では、文字列は可能であれば数値に変換されましたが、比較演算では文字列から数値への変換は自動的には行われません。そのため、0 == "0"falseとなります。数値と文字列を比較したいときには、ライブラリ関数であるtonumberを用いて、0 == tonumber("0")とする方法があります。

大小比較には、大なり(>)、以上(>=)、小なり(<)、以下(<=)があります。大小比較でも型が違う場合は値の比較は行わず、falseになります。

値の比較について、数値は一般的な比較方法になります。文字列は、先頭の文字から1文字ずつ内部コード値を比較し、その大小で比較します。文字列の長さが違い、短い文字列のほうは長い文字列と先頭から比較しても一致しているときには、長い文字列の方が大きいと判定されます。

a = "a"; b = "a"; a == b ⇒ true
a = "a"; b = "b"; a > b ⇒ true
a = "aa"; b = "a"; a < b ⇒ true
    

テーブル型、関数型、ユーザーデータ型、スレッド型については、等号、不等号しか利用できません。両辺がまったく同じデータを指しているときだけ等号はtrueとなります。たとえば、テーブルですべての要素が等しいとしても、両辺が別のテーブルであればfalseとなります。

a = { 1 }; b = a; a == b ⇒ true
a = { 1 }; b = { 1 }; a == b ⇒ false
    

論理演算子

論理演算子には、論理否定(not)、論理和(or)、論理積(and)があります。

notは、後続する式の値がfalseまたはnilの場合にはtrueを、そうでない場合はfalseを返します。

orは、左辺の式の値がfalseでもnilでもなければ、その値を返します。左辺がfalseまたはnilの場合は、右辺の式の値を返します。

andは、左辺の式の値がfalseまたはnilの場合には、その値を返します。左辺がfalseでもnilでもない場合は、右辺の式の値を返します。

orandでは、右辺の式は、その値が必要になるまで評価されません。たとえば、右辺が関数呼び出しであったとしても、左辺の値でorand演算の結果が確定した場合は、右辺の関数が呼び出されることはありません。

function f(x)
  print("called function f with ", x)
  return x + 1
end

a = 1
b = 1
c = (a == b) or f(10) -- fは呼び出されず、fの中のprintも実行されない
    

連結演算子

連結演算子は2つのピリオド(..)で表され、左辺と右辺の文字列を連結します。両辺の式の値が数値だった場合は、tostring関数で文字列に変換してから連結します。

a = "Hello "
b = "World"
c = a .. b  -- ⇒ "Hello World"

a = 1
b = 2
c = a .. b  -- ⇒ "12"
    

長さ演算子

長さ演算子はシャープ(#)で表され、後続する式の値の長さを返します。

文字列の長さは、文字列のバイト数です。

#"Hello World" ⇒ 11
#"こんにちは"  ⇒ 10
    

テーブルtの長さは、t[n]nilではなく、t[n+1]nilであるnと定義されています。テーブルが配列であれば、長さ演算子はテーブルの要素数を返します。しかし、途中にnilがあり、この条件に一致するnが複数ある場合には、どれが返されるかは予測できません。以下では、2行目と3行目は同じ形のテーブルに長さ演算子を使用していますが、結果は変わってきます。

#{ "a", "b", "c" } ⇒ 3
#{ "a", nil, "c" } ⇒ 3
#{ "a", nil, [3] = "c" } ⇒ 1
    

優先順位

演算子には優先順位があり、優先順位の高いものから先に演算が実行されていきます。Lua言語での演算子の優先順位は以下のようになっています。

 高い
  ^
  not, #, -(単項)
  *, /, %
  +, -(二項)
  ..
  ==, ‾=, >, >=, <, <=
  and
  or
 低い
    

また、カッコ(())を使って式を囲むことで優先順位を変えることができます。

累乗(^)と連結(..)は右結合です。すなわち、a^b^cは、a^(b^c)という順序で演算が行われます。その他の二項演算子はすべて左結合です。

関数定義

Lua言語では、関数定義は文ではなく、関数を返す式の要素です。関数定義は、以下の書式になります。

function 名前 (引数リスト)
  ブロック
end

名前 = function (引数リスト)
  ブロック
end
    

これら二つの書式は、まったく同じ内容を表しています。プログラムの意味としては後者の代入文が唯一の関数定義となります。つまり、上の書式の「名前」で表される変数は他の変数とは何の区別もなく、関数型の値を代入されている変数である、ということになります。

function f(x) print(x) end
function g(x) print(x + 1) end

f(1)          -- '1'が表示される
g(1)          -- '2'が表示される
f = g         -- エラーではない
f(1)          -- '2'が表示される
f = 10        -- エラーではない
f(1)          -- エラー、fの値(10)は関数ではない
    

また、以下のようにlocalと一緒に関数を定義すると、ローカル変数に関数を代入できます。

local function 名前 (引数リスト)
  ブロック
end

local 名前; 名前 = function (引数リスト)
  ブロック
end
    

やはり、前者と後者は同じ意味になります。後者の書き方であれば、関数内で自分自身を呼び出すことができます。ローカル変数のスコープは、local文の次の文から始まるため、以下の書き方では、関数内で自分自身を呼び出せないことに注意して下さい。

local 名前 = function (引数リスト)
  ブロック
end
    

引数リストは、仮引数となる変数名をコンマ(,)で列挙したものです。仮引数はまったくなくても構いません。仮引数は、関数内でローカルであるとされ、関数を呼び出したときの実引数で初期化されます。

引数リストの最後に、可変長引数として3つのピリオド(...)を書くことができます。明示された仮引数の数を越える実引数を渡されたとき、仮引数の最後に...があれば、後続の実引数には...を初期化部に持つテーブル経由でアクセスできます。

function f(...)
  local a = { ... }
  print(a[1], a[2], a[3])
end

f(1, 2, 3)
    

この例では、関数fは0個以上の引数を受け取り、先頭から3つの値を表示します。

関数の結果を返すには、return文を使います。return文がない場合には、関数は何も返しません。

また、コロン(:)を使った書き方もあり、メソッドと呼ばれます。メソッドでは、以下のような変換が行われます。

function 名前1:名前2(…) … end

名前1.名前2 = function (self, …) … end
    

名前2は、名前1のテーブルのキー文字列です。また、引数の先頭にselfが追加されます。この引数は、関数呼び出し時には名前1の変数の値に初期化されます。

メソッドは、組み込みライブラリの中の入出力関数で利用されています。

Luaスクリプトは、文の羅列でできています。文と文の間には空白や改行を置けば適切に解釈されますが、区切りが分かりにくいときには「;」(セミコロン)を置いても構いません。

文には以下のような種類があります。

代入文

代入文は、変数に値を代入するための文です。以下のような書式になります。

変数リスト = 式リスト
    

変数リストは、変数をコンマ(,)で並べたもの、式リストは式をコンマ(,)で並べたものです。

イコール(=)の左辺に書かれた変数のリストに対して、右辺の式の値が代入されます。たとえば、以下では変数aに値1を代入しています。

a = 1
    

また、Lua言語では、複数の変数への代入を一度に行うことができます。以下では、変数abにそれぞれ値12を代入しています。

a, b = 1, 2
    

右辺の式の評価はすべての代入が行われるよりも前に実行されるため、以下の例のように書くと変数abの値を入れ替えることができます。

a, b = b, a
    

制御文

制御文は、文の実行順序を変更したり、繰り返し実行したりするための文です。制御文には以下の種類があります。

if文

if文は、式の値に応じて複数の処理のうちどれか一つだけを実行する、という動作をします。if文は以下のような書式になります。

if 式1 then
  THENブロック
elseif 式2 then ELSEIFブロック
else ELSEブロック
end

式1の値がfalseもしくはnilでない場合、式1は真となり、THENブロックが実行されます。THENブロックが実行された後は、if文全体が終了し、endの次の文から処理が続きます。

式1の値がfalseもしくはnilである場合には、式1は偽となり、THENブロックは実行されずに次のelseifあるいはelseに続きます。

式1が偽でelseifが存在する場合、式2の値が調べられ、式1と同様に真であればELSEIFブロックが実行されます。elseifは複数存在してよく、式の値は書かれた順に調べられ、真である式が現れたときに該当するELSEIFブロックが実行され、if文は終了します。

すべての式が偽であり、elseがあるときには、ELSEブロックの文が実行されます。

なお、elseifは0個以上何個あっても構いません。elseは存在しないか、一つだけ存在するかです。

while文

while文は条件が一致している間、実行を繰り返します。while文の書式は以下のようになります。

while 式 do
  ブロック
end
    

まず最初に式を評価し、それが真、つまり、式の値がfalseまたはnilではなければ、ブロックを実行し、また式の値の評価に戻ります。

repeat-until文

repeat-until文は条件が一致するまでの間、実行を繰り返します。while文とは、式の値を評価するタイミングが異なります。repeat-until文の書式は以下のようになります。

repeat
  ブロック
until 式
    

まず最初にブロックを実行し、その後、式を評価します。式の値が偽、つまり、式の値がfalseまたはnilであれば、ブロックの実行に戻ります。

repeat-until文のブロック中で宣言したローカル変数は、until後の式の終わりまで有効です。

数値for文

数値for文は、カウンタ変数を一定値ずつ増やしながらブロックの実行を繰り返します。数値for文の書式は以下のようになります。

for 変数 = 初期値, 終了値 , 増分 do
  ブロック
end
    

数値for文では、変数にまず初期値が設定され、ブロックが実行されます。その後、変数は増分だけ増やされながら、ブロックが実行されます。そして、変数が終了値を超えたら終了します。

増分が省略されたときには、増分として1が使われます。また、増分には負の数も使用できます。

数値for文でカウンタとして使われる変数は、そのfor文にローカルであるとされます。つまり、for文が終了した後にカウンタ変数を読み出しても、カウンタとしての値は読み出せません。

一般for文

一般for文は、イテレータ(繰り返し)関数と呼ばれる特殊な関数を利用して繰り返し実行を行います。一般for文の書式は以下のようになります。

for 変数リスト in イテレータ関数 , 状態 , 初期値 do
  ブロック
end
    

変数リストは、イテレータ関数の戻り値になります。状態と初期値は、イテレータ関数を呼び出すときの引数で、初期値についてはループのたびに変数リストの先頭の値に変わっていきます。状態と初期値は省略されるとnilとなります。また、イテレータ関数がnilを返すとループは終了します。

通常、イテレータ関数、状態、初期値の三つ組みは、その3つの値を返すライブラリ関数を呼び出すことで求めるため、これらの三つ組みを意識することはありません。イテレータ関数、状態、初期値の三つ組みを返すライブラリ関数としては、テーブルのすべての要素を列挙するpairs()配列の要素を列挙するipairs()、文字列の中からパターンに一致する部分文字列を列挙するstring.gsub()などがあります。たとえば、以下の例ではテーブルtの要素をすべてprintで表示しています。

for key, value in pairs(t) do
  print(key, value)
end
    

変数リストで列挙する変数は、数値for文と同様、そのfor文にローカルであるとされます。

do文

do文はローカル変数の有効範囲であるスコープを設定するために用います。

do
  ブロック
end
    

break文

break文は、最も内側のループ(while文、repeat-until文、数値/一般for文)を終了させます。break文をループの外側で使うことはできません。

break
    

break文は、ブロックの最後にある必要があります。普通にプログラムを書けば、break文は必ずブロックの最後に来るので特に気にする必要はありませんが、デバッグなどの理由でbreak文をブロックの途中におく必要がある場合には、以下のようにdo文でその場限りのブロックを作る方法があります。

do break end
    
Lua言語には、ループを完全に終了するbreak文はありますが、C言語でのcontinue文のような、ループの今の回を終了し、次の回を強制的に始めるための制御文はありません。

return文

return文は、関数定義の中で使われ、関数の実行を終了して値を返します。return文は複数の値を返すことができます。return文を関数定義の外で使うことはできません。

return 式1 , 式2…
    

return文も、break文同様ブロックの最後にある必要があります。return文をブロックの途中におく必要がある場合には、やはりbreak文同様に、do文でその場限りのブロックを作ります。

do return end
    

関数呼び出し文

関数呼び出し文は、関数を呼び出しているだけの文です。関数は実行されますが、戻り値は捨てられます。関数呼び出し文は以下のような書式になります。

式1 (式2, …)
    

式1を評価した値が関数であれば、後続のカッコ内の値を引数として関数を呼び出します。最も普通のパターンでは式1としては単に関数の名前が使われます。

たとえば、今まで例によく使ってきたprintも関数です。ですから、以下の例ではいずれもprint関数が呼び出されます。

print(1)
f = print
f(1)
g = f
g(1)
    

特殊なケースとして、引数が1つで、それが文字列リテラルか、テーブルコンストラクタである場合に限り、関数呼び出しのためのカッコを省略することができます。たとえば、以下はすべて正しい関数呼び出しとなります。

print "Hello, world"     -- 関数printを、"Hello, world"という引数一つだけで呼び出している

require "strict"         -- 関数requireを、"strict"という引数一つだけで呼び出している

t = table.sort{4,2,3,1}  -- 関数table.sortを、{4,2,3,1}という引数一つだけで呼び出している
    

一方で、以下はエラーです。

a = "Hello, world"
print a                   -- aは文字列型だが文字列リテラルではないので、カッコは省略できない

table.insert{4,2,3,1}, 5  -- 関数table.insertは最低2つの引数が必要なので、カッコは省略できない
    

ローカル変数宣言文

ローカル変数宣言文では、変数のスコープ、有効範囲がローカルであると宣言します。ローカル変数宣言文で宣言された変数は、その宣言文の次の文からブロックの最後まで有効となります。ローカル宣言文の書式は以下のようになります。

local 変数リスト = 式リスト
    

式リストがあれば、変数は代入文と同じルールでそれぞれ値が初期化されます。式リストがない場合は、nilで初期化されます。

チャンクとブロック

Luaでは、文の羅列をチャンクと呼びます。Luaスクリプトはすべてチャンクです。チャンクの中でも、ローカル変数のスコープ(有効範囲)を決めるものはブロックと呼びます。以下はすべてブロックです。

スコープ

スコープとは変数の有効範囲のことです。

ローカル変数のスコープは、ローカル変数宣言文の次の文から始まり、ローカル変数宣言文が含まれているブロックが終わるまで、となります。この場合、ローカル変数宣言文の初期化式は、ローカル変数のスコープには含まれないことに注意してください。

グローバル変数には明示的な宣言文がありません。グローバル変数が最初に現れたときが、スコープの始まりとなり、プログラムの最後までグローバル変数は有効です。

また、Lua言語はレキシカルスコープを採用しています。これは、ブロックの内側から、ブロックの外側で宣言された変数にアクセスできる、ということを意味しています。

x = 10                 -- グローバル変数 'x'
y = 20                 -- グローバル変数 'y'
do                     -- 新しいブロック
  local x = x          -- 新しい変数 'x'、値は 10
  print(x)             -- 10
  print(y)             -- 20
  x = x + 1
  do                   -- 別のブロック
    local x = x + 1    -- 別の新しい 'x'
    print(x)           -- 12
    print(y)           -- 20
  end
  print(x)             -- 11
  print(y)             -- 20
end
print(x)               -- 10  (グローバル変数)
print(y)               -- 20
    

上では、変数xはブロックのたびごとに新しいローカル変数を宣言されているので、ブロックの中ではそのブロックで宣言されたローカル変数を扱うことになるのに対し、変数yはどこでも最上位のグローバル変数をアクセスすることになります。

グローバル変数には明示的な宣言文がないため、タイプミスに弱くなっています。タイプミスでいきなり新しい変数名が出てきても、Luaスクリプトはエラーとは考えずにその値がnilであるとして処理を進めます。タイプミスには注意してください。

Lua 5.1.4/5.1.5の配布パッケージに含まれているstrict.luaを用いると、グローバル変数のタイプミスによる間違いをある程度防ぐことができます。詳しくは、strict.luaの使い方を参照してください。

複数値の取り扱い

Lua言語では、関数呼び出しの結果と、可変長引数で複数の値を扱うことができます。これらの複数の値は、式の中で扱われるときには、その時々の適切な長さに調節されます。

関数呼び出しが、式の一部ではなく、単独で文となっている場合には、戻り値の複数の値はすべて捨てられます。

function f()
  return 1, 2, 3  -- 複数の値を戻り値として返す
end

f()               -- 返ってきた複数の戻り値はすべて捨てられる
    

複数の値が他の式の中の要素として表れた場合は、先頭の値のみが用いられ、後続の値は捨てられます。特に、カッコに囲むことで先頭の値のみを用いることを強制できます。

function f() return 1, 2, 3 end

a = f() + 1    -- f()の戻り値は'1'のみが使われ、aは2となる
a, b = (f())   -- f()の戻り値は'1'のみが使われ、aは1、bはnilとなる
    

複数の値がリスト(代入文の右辺、local文の初期化部、テーブルコンストラクタの初期化部、関数呼び出しの実引数)の途中に表れた場合も、先頭の値のみが用いられ、後続の値は捨てられます。

function f() return 1, 2, 3 end

a, b, c = f(), 10   -- f()の戻り値は'1'のみが使われ、aは1、bは10、cはnilとなる

function g(...)
  t = { ..., 10 }   --t[1]がg()を呼び出した時の実引数の先頭の値となり、t[2]は10となる
end

g(f(), 10)          -- f()の戻り値は先頭の'1'のみが使われ、g()は、g(1, 10)として呼び出される
    

複数の値がリストの最後に表れた場合は、複数の値が必要なだけすべて使用されます。

function f() return 1, 2, 3 end

a, b, c = 10, f()        -- f()の戻り値はすべて使われ、aは10、bは1、cは2となる
                         -- f()の戻り値の最後の'3'は代入する変数がないので捨てられる

function g(...)
  t = { ... }  --tの各要素にg()を呼び出した時の実引数がすべて代入される
end

g(f())                   -- f()の戻り値はすべて使われ、g()は、g(1, 2, 3)として呼び出される。
    

コメント

コメントは、文字列の外ならどこにでも記述することができ、プログラムの実行上はコメント全体が一つの空白文字と同じものとみなされます。コメントには短い形式と長い形式があります。

短い形式のコメントは、二つのハイフン(--)で始まり、行の終わりまで続きます。二つのハイフンの直後は開きロングカッコであってはいけません。

長い形式のコメントは、二つのハイフン(--)の直後に、開きロングカッコ([[[==[等)がある字句から始まり、同じレベルの閉じロングカッコ(]]]==]等)で終わります。二つのハイフンと開きロングカッコの間には空白も含め何も文字があってはいけません。

長い形式のコメントは、複数行にわたるコメントや、行中にコメントを書くときに使用します。

-- 行全体がコメント
--[[
  複数行のコメント
]]
a = 1 --[[行中のコメント]] + 2
    

エラー

エラーには、文法のエラーや型のエラーなどがありますが、原則としてエラーが発生するとLuaスクリプトはスクリプト全体の実行を停止し、エラーメッセージを出力します。例外として、以下の関数経由で呼び出した処理の中で発生したエラーは、それぞれの関数の戻り値に反映され、スクリプト全体の動作は停止しません。


←前 目次
次→