DAY 29
0
Software Development

# Meta Programming / 元程式設計

``````A = 1
B = 2
C = 3
-- ....
Z = 26
``````

``````for i=65, 65+25 do  -- ASCII Code of A is 65
print(string.char(i))
_ENV[string.char(i)] = i - 64 -- 1 to 26
end
``````

# metatable / 元表

`metatable`是Lua對於`table`一個特殊的屬性。每個`table`都可以設定另一個`table`作為其`metatable``metatable`可以設定/改變該`table`的部份行為。

## `setmetatable`

``````MetaPyStr = {}
PyStr = {"Hello, "}

setmetatable(PyStr, MetaPyStr)
``````

## `getmetatable`

``````meta = getmetatable(PyStr)
``````

## 改變`table`行為

`metatable`是用於描述`table`相關的物件，其可以設定/改變該`table`的部份行為。舉例來說，正常的`table`使用`tostring()`或是`print()`得到的結果可能不那麼好理解：

``````print(PyStr)
--> table: 0x555de2908880

print(tostring(PyStr))
--> table: 0x555de2908880
``````

``````MetaPyStr = {
__tostring = function(PyStr)
return '<PyStr "' .. PyStr[1] .. '">'
end
}

setmetatable(PyStr, MetaPyStr)

print(PyStr)
--> <PyStr "Hello, ">
``````

``````function MetaPyStr:__tostring()
return self[1]
end

print(PyStr)
--> "Hello, "
``````

# 運算子多載

``````"Hello, " + "World" # => "Hello, World"
"Hello, " * 3 # => 'Hello, Hello, Hello, '
``````

``````function PyStr(str)
assert(type(str) == 'string',
'str must is a string')
local _PyStr = {str}

setmetatable(_PyStr, MetaPyStr)
return _PyStr
end

print(PyStr("Hello, "))
--> Hello,
``````

``````function MetaPyStr:__add(other --[[PyStr]])
assert(type(other) == "table")
assert(type(other[1] == 'string'))

return self[1] .. other[1]
end

function MetaPyStr:__mul(times --[[integer]])
times =math.tointeger(times)
assert(times)  -- check times is integer

local new_PyStr = {self[1]}
setmetatable(new_PyStr, MetaPyStr) --  set new_PyStr is Pystr

for _=2,times do
new_PyStr[1] = new_PyStr[1] .. self[1]
end

return new_PyStr
end

hello = PyStr("Hello, ")
world = PyStr("World")

print(hello + world)
--> Hello, World

print(hello * 3)
--> Hello, Hello, Hello,
``````

``````function MetaPyStr:new(str --[[string]])
assert(type(str) == 'string'
, 'str must is a string')
local _PyStr = {str}
setmetatable(_PyStr, self)
return _PyStr
end

hello = MetaPyStr:new("Hello, ")
print(hello)
--> Hello,
``````

`MetaPyStr:new`像不像Ruby的用法？
Ruby使用`initialize`去初始話物件，使用`class.new`去建立實體。
Lua也可以實現類似設計。有興趣嘗試模擬一下吧！

`function MetaPyStr:new`這樣的語法糖，直接為`MetaPyStr`添加新的方法，是不是也很像Ruby的開放式類別(Open Classes)。

## 其他運算子

• `__add`
加法運算(`+`)
• `__sub`
剪法運算(`-`)
• `__mul`
乘法運算(`**`)
• `__div`
除法運算(`/`)
• `__idiv`
整數除法運算(`//`)
• `__mod`
取模運算(`%`)
• `__eq`
相等運算(`==`)
• `__concat`
連接運算(`..`)

30天 Lua重拾筆記36