--[[1]] foo = {} foo.key = 'value' --[[2]] mt = {__index = foo} -- setmetatable --[[3]] bar = setmetatable({}, mt) bar.key2 = 'value2' -- : --[[4]] print('bar.key2', bar.key2) --> 'value2' --[[5]] print('bar.key', bar.key) --> 'value' --[[6]] bar.key = 'foobar' foo.foo = 'snafu' print('bar.key', bar.key) --> 'foobar' print('bar.foo', bar.foo) --> 'snafu' print('bar.foobarsnafu', bar.foobarsnafu) --> nil --[[7]] foo = {key = 'FooBar'} -- bar = setmetatable({}, {__index = foo}) snafu = setmetatable({}, {__index = bar}) print('snafu.key', snafu.key) --> 'FooBar' --[[8]] foo = {} foo.__index = foo setmetatable(foo, foo) -- print('foo.key', foo.key) --> error: loop in gettable print('foo.__index', foo.__index) --> "table: 0x12345678" print('rawget(foo, "key")', rawget(foo, "key")) --> nil --[[9]] foo = {} foo.key = 'value' setmetatable(foo, {__index = function(self, key) return key end}) print('foo.key', foo.key) --> 'value' print('foo.value', foo.value) --> 'value' print('foo.snafu', foo.snafu) --> 'snafu' --[[10]] fibs = { 1, 1 } setmetatable(fibs, { __index = function(self, v) self[v] = self[v - 1] + self[v - 2] return self[v] end })
--[[1]] foo = {} mt = {} function mt.__newindex(self, key, value) foo[key] = value end bar = setmetatable({a = 10}, mt) bar.key = 'value' print('bar.key', bar.key) --> nil print('foo.key', foo.key) --> 'value' --[[2]] bar.a = 20 print('bar.a', bar.a) --> 20 --[[3]] mt = {} function mt.__newindex(self, key, value) if type(value) == 'number' then -- __newindex rawset(self, key, value) end end foo = setmetatable({}, mt) foo.key = 'value' foo.key2 = 100500 print('foo.key', foo.key) --> nil print('foo.key2', foo.key2) --> 100500
--[[1]] mt = {} function mt.__call(self, a, b, c, d) return a..b..c..d end foo = setmetatable({}, mt) foo.key = 'value' print(foo(10, 20, 30, '!')) --> 102030! print(foo.key) --> 'value' print(foo.bar) --> nil --[[2]] mt = {} -- - , -- : a, b, c, d = ... function mt.__call(self, ...) return self.default(...) end foo = setmetatable({}, mt) function foo.mul2(a, b) return a * b end function foo.mul3(a, b, c) return a * b * c end foo.default = foo.mul2 print('foo.mul2(2, 3)', foo.mul2(2, 3)) --> 6 print('foo.default(2, 3)', foo.default(2, 3)) --> 6 print('foo.mul3(2, 3, 4)', foo.mul3(2, 3, 4)) --> 24 -- . print('foo(2, 3)', foo(2, 3)) --> 6 foo.default = foo.mul3 print('Default was changed') print('foo(2, 3, 4)', foo(2, 3, 4)) --> 24
mt = {} function mt.__tostring(self) return '['..table.concat(self, ', ')..']' end foo = setmetatable({}, mt) foo[1] = 10 foo[2] = 20 foo[3] = 30 print('foo', foo) --> [10, 20, 30] -- print('foo..foo', foo..foo) -- ! ! function mt.__concat(a, b) return tostring(a)..tostring(b) end print('foo.."!"', foo.."!") --> [10, 20, 30]! print('"!"..foo', "!"..foo) --> ![10, 20, 30] print('foo..foo', foo..foo) --> [10, 20, 30][10, 20, 30]
mt = {} mt.id = 12345 foo = setmetatable({}, mt) print(getmetatable(foo).id) --> 12345 mt.__metatable = 'No metatables here!' print(getmetatable(foo)) --> 'No metatables here!' mt.__metatable = false print(getmetatable(foo)) --> false
--[[1]] mt = {__mode = 'v'} foo = setmetatable({}, mt) --[[2]] bar = {foobar = 'fu'} foo.key = bar foo.key2 = {barfoo = 'uf'} foo[1] = 100500 --[[3]] print('foo.key.foobar', foo.key.foobar) --> 'fu' print('foo.key2.barfoo', foo.key2.barfoo) --> 'uf' print('foo[1]', foo[1]) --> 100500 collectgarbage() print('foo.key.foobar', foo.key.foobar) --> 'fu' print('foo[1]', foo[1]) --> 100500 -- print('foo.key2.barfoo', foo.key2.barfoo) --> , key2 ! --[[4]] bar = nil collectgarbage() -- print('foo.key.foobar', foo.key.foobar) --> , key !
mt = {} function mt.__gc(self) print('Table '..tostring(self)..' has been destroyed!') end -- lua 5.2+ foo = {} setmetatable(foo, mt) -- Lua 5.1 if _VERSION == 'Lua 5.1' then -- __gc 5.1 cdata-. -- - , . -- 'foo', local t = foo -- newproxy cdata-, Lua 5.1. local proxy = newproxy(true) -- __gc cdata - __gc- foo getmetatable(proxy).__gc = function(self) mt.__gc(t) end foo[proxy] = true end print(foo) foo = nil collectgarbage() --> 'Table 0x12345678 has been destroyed!'
mt = {} function mt.__len(self) local keys = 0 for k, v in pairs(self) do keys = keys + 1 end return keys end foo = setmetatable({}, mt) foo[1] = 10 foo[2] = 20 foo.key = 'value' print('#foo', #foo) --> 3 (2 Lua 5.1)
mt = {} function mt.__pairs(self) local key, value = next(self) return function() key, value = next(self, key) -- - . while key and type(key) == 'number' do key, value = next(self, key) end return key, value end end function mt.__ipairs(self) local i = 0 -- ipairs . return function() i = i - 1 return self[i] and i, self[i] end end foo = setmetatable({}, mt) foo[1] = 10 foo[2] = 20 foo[-1] = -10 foo[-2] = -20 foo.foo = 'foobar' foo.bar = 'barfoo' -- Lua 5.1 , -- 5.2+ - for k, v in pairs(foo) do print('pairs test', k, v) end --> foo foobar --> bar barfoo -- Lua 5.1 , -- 5.2+ - for i, v in ipairs(foo) do print('ipairs test', i, v) end --> -1 -10 --> -2 -20
]] --[[1]] vector_mt = {} function vector_mt.__add(a, b) local v = {} vx = ax + bx vy = ay + by return setmetatable(v, vector_mt) end function vector_mt.__div(a, b) local v = {} vx = ax / bx vy = ay / by return setmetatable(v, vector_mt) end -- function vector_mt.__tostring(self) return '['..self.x..', '..self.y..']' end vec1 = setmetatable({}, vector_mt) vec1.x = 1 vec1.y = 2 vec2 = setmetatable({}, vector_mt) vec2.x = 3 vec2.y = 4 vec3 = vec1 + vec2 print('vec3', vec3) --> [4, 6] print('vec2 / vec1', vec2 / vec1) --> [3, 2] --[[2]] mt = {} function mt.__add(a, b) local insert_position = 1 if type(a) == 'table' and getmetatable(a) == mt then insert_position = #a + 1 else a, b = b, a end table.insert(a, insert_position, b) return a end -- function mt.__tostring(self) return '['..table.concat(self, ', ')..']' end foo = setmetatable({}, mt) --[[3]] foo = 3 + 4 + foo + 10 + 20 + 'a' + 'b' print('foo', foo) --> [7, 10, 20, a, b] foo = '12345' + foo print('foo', foo) --> [12345, 7, 10, 20, a, b]
function Class() local class = {} -- . local mClass = {__index = class} -- , "" . function class.instance() return setmetatable({}, mClass) end return class end -- . Rectangle = Class() function Rectangle.new(x, y, w, h) local self = Rectangle.instance() self.x = x or 0 self.y = y or 0 self.w = w or 10 self.h = h or 10 return self end function Rectangle.area(self) return self.w * self.h end -- rect = Rectangle.new(10, 20, 30, 40) print('rect.area(rect)', rect.area(rect)) --> 1200 print('rect:area()', rect:area()) --> 1200
foo = {x = 10, y = 20} function foo.bar(self, a, b) return (self.x + a) * (self.y + b) end print('foo.bar(foo, 1, 2)', foo.bar(foo, 1, 2)) --> 242 -- , self "" . function foo:bar(a, b) return (self.x + a) * (self.y + b) end print('foo:bar(1, 2)', foo:bar(1, 2)) --> 242
function Class(parent) local class = {} local mClass = {} -- . -- . class.__index = class -- __index, -- , , . mClass.__index = parent -- Super . class.Super = parent -- , function mClass:__call(...) local instance = setmetatable({}, class) -- "init" if type(class.init) == 'function' then -- init return instance, instance:init(...) end -- - . return instance end return setmetatable(class, mClass) end -- . Shape = Class() function Shape:init(x, y) -- self . self.x = x or 0 self.y = y or 0 return '!!!' end function Shape:posArea() return self.x * self.y end -- Shape , -- . function Shape:__tostring() return '[' .. self.x .. ', ' .. self.y ..']' end local foo, value = Shape(10, 20) print('foo, value', foo, value) --> [10, 20] !!! -- Rectangle = Class(Shape) function Rectangle:init(x, y, w, h) -- , self - , -- Rectangle, . -- Super. self.Super.init(self, x, y) -- - . self.w, self.h = self:getDefault(w, h) end function Rectangle:area() return self.w * self.h end function Rectangle:getDefault(w, h) return w or 10, h or 20 end function Rectangle:__tostring() return '['..self.x..', '..self.y..', '..self.w .. ', '..self.h..']' end rect = Rectangle(10, 20, 30, 40) print('rect', rect) --> [10, 20, 30, 40] print('rect:area()' , rect:area()) --> 30 * 40 = 1200 -- print('rect:posArea()', rect:posArea()) --> 10 * 20 = 200
function proxy() local real_table = {} local logger = {} local metatable = {} -- function metatable:__index(key) local value = rawget(real_table, key) table.insert(logger, "Get key "..tostring(key)..' is '.. tostring(value)) return value end -- , function metatable:__newindex(key, value) table.insert(logger, "Set key "..tostring(key)..' as '..tostring(value)) rawset(real_table, key, value) end return setmetatable({}, metatable), logger end prox, log = proxy() prox.a = 10 prox.a = 20 print('prox.a', prox.a) --> 20 print('log', '\n'..table.concat(log, '\n')) --> Set key a as 10 --> Set key a as 20 --> Get key a, is 20
page = {} page.https = require'ssl.https' page.cache = setmetatable({}, {__mode = 'v'}) -- page._meta = {} function page._meta:__tostring() return 'Page: ['..self.url.. ']: '.. self.status end setmetatable(page, page) function page:__call(url) return self.cache[url] or self:request(url) end function page:request(url) local page = setmetatable({}, self._meta) page.url = url page.data, page.status, page.error, page.hate = self.https.request(url) print(page.data, page.status, page.error, page.hate) self.cache[url] = page return page end -- , , . p = page('https://yandex.ru') print('p', p) --> Page: [https://yandex.ru]: 200 print('p.status', p.status) --> 200 -- , -- - . print('page.cache[...]', page.cache['https://yandex.ru']) --> Page: [https://yandex.ru]: 200 -- , "p". collectgarbage() print('page.cache[...]', page.cache['https://yandex.ru']) --> Page: [https://yandex.ru]: 200 p = nil collectgarbage() -- - , . print('page.cache[...]', page.cache['https://yandex.ru']) --> Nil
Source: https://habr.com/ru/post/346892/
All Articles