M.Hiroi's Home Page

お気楽 Lua プログラミング超入門

Lua の基礎知識 (データ構造編)


Copyright (C) 2011-2019 Makoto Hiroi
All rights reserved.

はじめに

Lua はC言語や Perl と同じく、手続き型のプログラミング言語です。Lua も Perl と同様に、プログラムの実行を制御する「文」(命令文ともいう)、データを格納する「変数」、決められた処理を行う「関数」、という構造に分かれます。C言語や Perl のように、文の終わりにセミコロン ( ; ) を付ける必要はありません。コメントは -- から行末まで、もしくは --[[ から ]] の間に記述します。

変数と関数は名前をつけて区別します。名前には英数字とアンダースコア _ が使えます。ただし、数字から始まる名前は定義できません。英大文字と英小文字は区別されるので、FOO と Foo と foo は異なる名前と判断されます。関数は Lua にあらかじめ用意されている「組み込み関数」のほかに、私達ユーザーが定義することもできます。もちろん「再帰定義」も可能です。

●数

それでは、Lua に用意されている基本的なデータ型について簡単に説明しましょう。Lua の数には「整数 (integer)」と「浮動小数点数 (floating point number)」の二種類があります。整数は ver 5.3.0 からサポートされました。それ以前のバージョンでは整数はなく、数は浮動小数点数になります。通常、整数の範囲は -9223372036854775808 から 9223372036854775807 (64 bit) までです。浮動小数点数はC言語の double と同じで、範囲は絶対値で約 1e-307 から 1e+308 までです。

簡単な例を示します。

> a = 100
> a
100
> b = 1.234
> b
1.234
> c = 10 + 20
> c
30
> d = 10 * 20
> d
200
> 10 - 20
-10
> 10 / 20
0.5
> 10 // 20
0
> 20 / 10
2.0
> 20 // 10
2

Lua はC言語と違い、変数のデータ型を宣言する必要はありません。変数に値をセットすることを「代入」といいます。代入には = を使います。これはC言語や Perl と同じです。対話モードで変数名を入力するとその値が表示されます。数は小数点を付けると浮動小数点数に、付けなければ整数として扱われます。表示も同様です。

主な算術演算子を表 1 に示します。

表 1 : 算術演算子
操作結果
-x x を負にする
x + y x と y の和
x - y x と y の差
x * y x と y の積
x / y x 割る y の商 (浮動小数点数)
x // y x 割る y の商 (小数点以下切り捨て)
x % y x 割る y の剰余
x ^ y x の y 乗 (累乗)

基本的に、整数と整数の演算結果は整数に、それ以外の演算結果は浮動小数点数になります。除算 / と累乗 ^ は引数を浮動小数点数に変換し、演算結果も浮動小数点数になります。

●ビット演算子

整数の導入とともに Lua はビット演算子をサポートするようになりました。ビット演算子は引数を整数に変換して演算処理を行い、その結果を整数として返します。Lua のビット演算子を表 2 に示します。

表 2 : ビット演算子
演算子操作
x & y ビットごとの論理積
x | y ビットごとの論理和
x ~ y ビットごとの排他的論理和
~x ビットごとの否定
x << y x を y ビット左シフト
x >> y x を y ビット右シフト

演算子 & はビットごとの論理積を返します。

5 & 3 => 1
     0101
 AND 0011
---------
     0001

演算子 l はビットごとの論理和を返します。

5 | 3 => 7
    0101
 OR 0011
--------
    0111

二項演算子 ~ はビットごとの排他的論理和を返します。

5 ~ 3 => 6
     0101
 XOR 0011
---------
     0110

単項演算子 ~ はビットごとの論理的な否定を返します。

~1 => -2
~0 => -1

<<, >> はビットをシフトする演算子です。左シフトの場合、下位ビットには 0 が挿入されます。右シフトの場合、上位ビットに 0 が挿入されます。したがって、負の整数を右シフトすると正の整数になります。いわゆる「算術シフト」ではないので注意してください。

1 << 8 => 256
1 << 16 => 65536
256 >> 8 => 1
65536 >> 16 => 1
1 << 63 => -9223372036854775808
(1 << 63) >> 1 => 4611686018427387904

●多重代入

演算子 = の左辺がカンマで区切られている場合、複数の代入を一度で行うことができます。これを「多重代入」といいます。

簡単な例を示しましょう。

> a, b = 10, 20
> a
10
> b
20
> a, b = b, a
> a
20
> b
10

変数 a と b に 10 と 20 を代入しています。a と b の値を交換する場合、多重代入を使えば簡単に行うことができます。

●文字列

文字列 (string) はシングルクオート ' で囲むか、ダブルクオート " で囲んで表します。

> a = "hello, world"
> a
hello, world

変数 a に文字列 "hello, world" を代入しています。文字列には演算子 .. を適用することができます。

> "abc" .. "def"
abcdef

演算子 .. は文字列を連結した新しい文字列を作ります。

文字列には「エスケープシーケンス」を含めることができます。これは、画面に表示することができない文字を表すのに用いられる方法です。よく使われる記号に改行を表す \n とタブを表す \t があります。

> "abc\ndef"
abc
def
> "abc\tdef"
abc     def

この例はタブが 8 文字に設定されている場合です。

このほかに、Lua には文字列を操作する便利な関数が用意されています。また、正規表現も利用することができます。

●数と文字列の変換

Lua は Perl と同様に、数が必要な演算に文字列が与えられると、文字列を数 (整数または浮動小数点数) に変換して処理を行います。数に変換できない場合はエラーになります。逆に、文字列が必要な演算で数が与えられると、数を文字列に変換して処理を行います。

簡単な例を示しましょう。

> 1 + "2"
3.0
> "1" + "2"
3.0
> 1 + "x"
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> 'abc' .. 10
abc10
> 1 .. 2
12

●配列

「配列 (array)」は複数のデータを格納するデータ構造です。配列に格納されたデータを要素といいます。特に、要素を一列に並べたものを 1 次元配列もしくは「ベクタ (vector)」と呼びます。

配列の要素は 1 以上の整数で指定します。これを「添字 (subscripts)」といいます。Lua の場合、C言語とは違って添字は 1 から始まることに注意してください。配列は中カッコ { と } で囲み、要素をカンマ ( , ) で区切って表します。{ } は要素が一つもない空の配列になります。

簡単な例を示します。

> ary1 = {1, 2, 3, 4, 5}
> ary1
table: 0x7fffe8e9cd70
> ary1[1]
1
> ary1[5]
5
> ary1[5] = 100
> ary1[5]
100

C言語は配列の大きさを宣言する必要がありますが、Lua の配列は大きさを宣言する必要はありません。配列の大きさは Lua が自動的に調整してくれます。大きさを自由に変えることができる配列を「可変長配列」といいます。Perl, Python, Ruby などのスクリプト言語でも可変長配列をサポートしています。

配列の要素には、いろいろなデータ型が混在していてもかまいません。また、要素に式を書くこともできます。

> ary2 = {"a", 1, "b", 2, "c", 3}
> ary2
table: 0x7fffe8e97680
> ary2[1]
a
> ary2[6]
3
> ary3 = {1 + 2, 3 * 4 - 5}
> ary3
table: 0x7fffe8e90cf0
> ary3[1]
3
> ary3[2]
7

ary2 の配列は、0, 2, 4 番目の要素が文字列で、1, 3, 5 番目の要素が整数になっています。要素に式を書くと、その式の評価結果が要素になります。

配列は入れ子にすることができます。つまり、配列の要素に配列を入れてもかまいません。これで多次元配列を表すことができます。

> ary4 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
> ary4[1][1]
1
> ary4[2][1]
4
> ary4[3][3]
9

ary4 のように、配列の中に配列を入れることで 2 次元配列を表すことができます。ary4 の 1 番目の要素は配列 {1, 2, 3} で、その配列の 1 番目の要素は 1 です。この要素は角カッコを 2 つ使って ary4[1][1] とアクセスすることができます。最初の ary4[1] で 1 番目の配列を取り出し、その配列の 1 番目の要素を次の [1] で取り出します。

●連想配列 (ハッシュ)

配列が数値を使って要素を指定するのに対し、「連想配列 (ハッシュ)」はキーというデータを使って要素を指定します。一般に、ハッシュのキーには文字列が用いられます。Lua の場合、配列はハッシュを使って実装されているので、キーが数値でも要素にアクセスすることができます。Lua の場合、配列やハッシュのことを「テーブル (table)」と呼びますが、本稿では配列とハッシュを区別して呼ぶことにします。

ハッシュは中カッコ '{' と '}' で囲み、要素をカンマで区切って表します。要素は「キー = 値」で指定します。キーは名前で指定します。キーを省略した場合、キーは数値 (添字) になります。この場合、「キー = 値」の要素をすべて取り除くと配列の定義と同じになるので、添字はそれと同じ値になると考えてください。 { } は要素が一つもない空のハッシュになります。

簡単な例を示します。

> d = {foo = 10, bar = 20}
> d
table: 0x7fffe8e969f0
> d["bar"]
20
> d["foo"]
10
> d.bar
20
> d.foo
10
> d["foo"] = 100
> d["foo"]
100
> d.foo = 1000
> d.foo
1000
> d["baz"]
nil
> d.baz = 1
> d.baz
1
> d.baz = nil
> d.baz
nil

ハッシュのアクセスは配列と同様に角カッコ [ ] を使うか、"ハッシュ + ドット ( . ) + 名前" で行います。最初にハッシュを生成して変数 d にセットします。d["foo"] または d.foo でキー foo の値を取り出したり、そこに値を代入すれば、d["foo"] の値を書き換えることができます。

値を取り出すとき、キーが見つからない場合は nil という特別な値を返します。通常、nil は値がないことを表すために使われます。新しいキー baz を追加する場合は、d["baz"] または d.baz に値を代入すると、ハッシュに "baz" とその値が追加されます。nil を代入すると、ハッシュからキーを削除することができます。


初版 2011 年 4 月 16 日
改訂 2019 年 12 月 28 日