MySQL- Руководство разработчика

Методы тэгов


Lua обеспечивает мощный механизм, чтобы расширить семантику, названный методами тэгов. Это определенная программистом функция, которая вызвана в специфических точках в течение выполнения программы Lua, позволяя программисту изменить стандартное поведение Lua в этих точках. Каждая из этих точек названа событием (event).

Метод тэга для некоего специфического события выбран согласно тэгу значения. Функция settagmethod изменяет метод тэга, связанный с данной парой (tag, event). Первый параметр представляет собой тэг, второй строку (имя события), а третий параметр (функция) задает новый метод или nil, чтобы восстановить заданное по умолчанию поведение для пары. Функция settagmethod возвращает предыдущий метод тэга для этой пары. Функция-компаньон gettagmethod получает тэг и имя события и возвращает текущий метод, связанный с парой.

Методы тэгов вызваны при соответствующих событиях, которые идентифицированы данными именами. Семантика методов лучше объяснена функцией Lua, описывающей поведение интерпретатора в каждом событии. Эта функция не только показывает, когда метод вызван, но также параметры, результаты и заданное по умолчанию поведение. Код, показанный здесь, только иллюстративен: реальное поведение сложно закодировано в интерпретаторе и намного более эффективно, чем это моделирование. Все функции, используемые в этих описаниях (rawget, tonumber, call и т.д.), описаны подробно в разделе 4.6.1.

``add'': Вызван, когда операция + применяется к не числовым операндам.

Функция getbinmethod ниже определяет, как Lua выбирает метод для двоичной операции. Сначала Lua пробует первый операнд. Если тэг не определяет метод для операции, то Lua пробует второй операнд. Если это также терпит неудачу, то Lua получает метод из тэга 0. function getbinmethod (op1, op2, event) return gettagmethod(tag(op1), event) or gettagmethod(tag(op2), event) or gettagmethod(0, event) end При использовании этой функции, метод события ``add'' такой: function add_event (op1, op2) local o1, o2 = tonumber(op1), tonumber(op2) if o1 and o2 then -- both operands are numeric return o1+o2 -- '+' here is the primitive 'add' else -- at least one of the operands is not numeric local tm = getbinmethod(op1, op2, "add") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "add") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end


``sub'': Вызван, когда операция - применяется к не числовым операндам. Поведение подобно событию ``add''.

``mul'': Вызван, когда операция * применяется к не числовым операндам. Поведение подобно событию ``add''.

``div'': Вызван, когда операция / применяется к не числовым операндам. Поведение подобно событию ``add''.

``pow'': Вызван, когда операция ^ (возведение в степень) применяется к числовым операндам. function pow_event (op1, op2) local tm = getbinmethod(op1, op2, "pow") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "pow") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end

``unm'': Вызван, когда одноместная операция - применяется к не числовому операнду. function unm_event (op) local o = tonumber(op) if o then -- operand is numeric return -o -- '-' here is the primitive 'unm' else -- the operand is not numeric. -- Try to get a tag method from the operand; -- if it does not have one, try a "global" one (tag 0) local tm = gettagmethod(tag(op), "unm") or gettagmethod(0, "unm") if tm then -- call the method with the operand, nil, and an extra -- argument with the event name return tm(op, nil, "unm") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end

``lt'': Вызван, когда операция порядка применяется к не числовому или не строчному операнду. Это соответствует оператору <. function lt_event (op1, op2) if type(op1) == "number" and type(op2) == "number" then return op1 < op2 -- numeric comparison elseif type(op1) == "string" and type(op2) == "string" then return op1 < op2 -- lexicographic comparison else local tm = getbinmethod(op1, op2, "lt") if tm then return tm(op1, op2, "lt") else error("unexpected type at comparison"); end end end Другие операторы порядка используют этот метод согласно обычным эквивалентностям: a>b <=> b<a a<=b <=> not (b<a) a>=b <=> not (a<b)



``concat'': Вызван, когда конкатенация применяется к не строчным операндам. function concat_event (op1, op2) if (type(op1) == "string" or type(op1) == "number") and (type(op2) == "string" or type(op2) == "number") then return op1..op2 -- primitive string concatenation else local tm = getbinmethod(op1, op2, "concat") if tm then return tm(op1, op2, "concat") else error("unexpected type for concatenation") end end end

``index'': Вызван, когда Lua пробует найти значение индекса, не представленного в таблице.

``getglobal'': Вызван всякий раз, когда Lua нуждается в значении глобальной переменной. Этот метод может быть установлен только для nil и для тэгов, порожденных вызовом newtag. Обратите внимание, что тэг представляет собой текущее значение глобальной переменной. function getglobal (varname) -- access the table of globals local value = rawget(globals(), varname) local tm = gettagmethod(tag(value), "getglobal") if not tm then return value else return tm(varname, value) end end Функция getglobal определена в базисной библиотеке. ``setglobal'': Вызван всякий раз, когда Lua присваивает значение глобальной переменной. Этот метод не может быть установлен для чисел, строк, таблиц и userdata с заданным по умолчанию тэгом. function setglobal (varname, newvalue) local oldvalue = rawget(globals(), varname) local tm = gettagmethod(tag(oldvalue), "setglobal") if not tm then rawset(globals(), varname, newvalue) else tm(varname, oldvalue, newvalue) end end Функция setglobal определена в базисной библиотеке.

``gettable'': Вызван всякий раз, когда Lua обращается к индексированной переменной. Этот метод не может быть установлен для таблиц с заданным по умолчанию тэгом. function gettable_event (table, index) local tm = gettagmethod(tag(table), "gettable") if tm then return tm(table, index) elseif type(table) ~= "table" then error("indexed expression not a table"); else local v = rawget(table, index) tm = gettagmethod(tag(table), "index") if v == nil and tm then return tm(table, index) else return v end end end



``settable'': Вызван, когда Lua присваивает значение индексированной переменной. Этот метод не может быть установлен для таблиц с заданным по умолчанию тэгом. function settable_event (table, index, value) local tm = gettagmethod(tag(table), "settable") if tm then tm(table, index, value) elseif type(table) ~= "table" then error("indexed expression not a table") else rawset(table, index, value) end end

``function'': Вызван, когда Lua пробует вызывать не функциональное значение. function function_event (func, ...) if type(func) == "function" then return call(func, arg) else local tm = gettagmethod(tag(func), "function") if tm then for i=arg.n,1,-1 do arg[i+1] = arg[i] end arg.n = arg.n+1 arg[1] = func return call(tm, arg) else error("call expression not a function") end end end

``gc'': Вызван, когда Lua начинает уборку мусора в userdata. Этот метод может быть установлен только из C, и не может быть установлен для userdata с заданным по умолчанию тэгом. Для каждого объекта userdata, который будет собран, Lua делает эквивалент следующей функции в цикле уборки мусора: function gc_event (obj) local tm = gettagmethod(tag(obj), "gc") if tm then tm(obj) end end В цикле уборки мусора методы тэгов для userdata вызываются в порядке, обратном созданию тэгов, то есть первые методы, которые будут вызваны, связаны с последним тэгом, созданным в программе. Кроме того, в конце цикла Lua делает эквивалент обращения gc_event(nil).


Содержание раздела