Luaの理解を深めたかった

# rluaでRustのプログラム内でLuaが動いても使いこなせないのはちょっとしょんぼりだな。

ということでLua自体の理解を深めようということになりました。
とはいえまるっきり知らないわけでもなく半端に知識があるところからの補間になるので誰かの役に立つかすら怪しい。自分用のメモなんだなとか思ってもらえればよいかと思う。

## 複数行のコメント

```lua
--[[
  コメント
--]]

--[[ コメント ]]
```

## != , && , ||, null

Luaで```!=```は```~=```になる。これは初めて見た。
強烈なので一発で覚えられたけど。

&&、||は andとor。Pythonと一緒。

nullは```nil```

## 文字列をつなぐ

```lua
a .. b

string.format("%s%s", a, b)
```
など

## 改行なしの文字表示

```lua
io.write("bra")
```

## forの書式
```lua
for i = start, end, <step> do
  print(i)
end
```
とか
```lua
for k, v in pairs(tbl) do
  print(k .. " :  " .. v)
end
```
とかする。

## do～end ブロック
とくにforとか専用というわけではなくそれ単体でも使える。
処理のかたまりの目安とかにもできる

## ++、 += など
Luaにそんなものはないので```a = a + 1```と、まじめに書く。

## OOP風
```lua
Member = {}
Member.new = function(name, age)
  local obj = {}
  obj.name = name
  obj.age = age
  obj.show = function(self)
    print(string.format("name: %s (%d)", self.name, self.age))
  end
  return obj
end

m = Member.new("Taro", 32)
m:show()
```
ポイントは最後の```m:show()```のコロン。自分自身のテーブルを引数として渡す動作をするので
関数のselfにmが入ることになる。
通常通りピリオドで処理した場合、自分自身の参照が必要なので```m.show(m)```と記述する必要があり少々冗長

## テーブルについて
テーブルは配列的にも使えるし連想配列的にも使える。
配列的に使う、この場合暗黙的にインデックス値がキーとして与えられており、シーケンシャルなデータとなる。結構有名な話としてLuaのシーケンスは1から始まる。
```lua
tbl = { 1, 2, 3 }
```
連想配列的に使う。Rustと同じく要素の順序は保証されない。
```lua
tbl = {"name" = "Hanako", age = 23 }
```
### 内容をとりだす
どちらの場合でもイテレーション処理で内容を取り出すことが出来る
```lua
for key, value in pairs(tbl) do
  print(key .. " :  " .. value
end
```
### 要素数を取得する
テーブルの要素は、シーケンシャルの場合は
```lua
#tbl
```
などとして取り出すことが出来るが連想配列的に利用している場合この方法では要素がどれだけあっても要素数0という答えになる。
イテレーション処理でカウントを取るなどして要素数を得る必要がある（ほんと？）

### 値の追加、削除
```lua
table.insert(tbl, {name="Alice", age=19})

table.remove(tbl)
```
table.insertとtable.removeを利用。
table.removeは最後のデータから削除される。

### ソート
```lua
table.sort(tbl)
```

### キー一覧を取得したい
そのような機能はないのでイテレーション処理で別のテーブルにキーを書き出すなどする。
あと、そのような処理が必要にならないように処理を見直した方がいいかもしれない。

## メタテーブルという仕組みがある
テーブルの実データに影響を与えないメタデータを記録したりできる機能
フラグの管理やデータの型の管理などに便利かもしれない？
必要そうになったらそういうものがあると思い出して調べる

## Luaでは関数も値
値なので変数に入る、テーブルにだって入る。
```lua
a = function(n); print(n); end
a(123)
```
```lua
b = {a,  ....}
```
## グローバル変数
```_VERSION```を取得すると現在動作中のLuaのバージョンが取得できる。
それ以外のグローバル変数は```_G```または```_ENV```にすべて入っている。

ということはPythonでは出来た```help("modules")```みたいなのが出来る。

```lua
help = function(name) 
    local e
    if name == "" or name == nil then
        e = _ENV
    else
        e = _ENV[name]
    end

    if name ~= nil then
        print(string.format("\n\n\"%s\" is %s", name, type(e)))
    end

    print("--------------------")

    if type(e) == "table" then
        for i in pairs(e) do
            print(i .. " ... " .. type(e[i]))
        end
    end

    print()
end
```

```
# help()
--------------------
rawset ... function
math ... table
dofile ... function
tostring ... function
（（中略））
_VERSION ... string
loadfile ... function
```
引数を指定しなければ全体を表示してくれる。
タイプとしてはfunction以外にtableやstring、numberなどがある。
tableについては次のように指定すれば中を調べられる。

```
help("math")
"math" is table
--------------------
min ... function
sqrt ... function
ldexp ... function
asin ... function
（（中略））
rad ... function
exp ... function
```

どういう関数が現在の環境で使えるのか調べることが出来る。
なんだ、Luaもできるんじゃん。

で、いちいちコード書き換えるのが面倒なのでREPLを作った。
```lua
local s
while true do 
    io.write("# ")
    s = io.read("*l")
    assert(load(s))()
end
```

先ほどのhelp functionと一緒に書いてやればコードを試したりしつつhelpで機能の確認などをすることが出来る。
わーお、便利だね。
でも簡易実装のREPLだからエラーがあると容赦なくストップする。

とりあえずこんなところかと思う。
他にも面白そうな話があれば追記したりするかもしれない。