Рассмотрим простейший пример того, что можно сделать при помощи декораторов:
local foo =
print_start_end(printor 'begin foo', printor 'end foo')
..
function (buzz)
print ('FOO called with ' .. buzz)
end
foo('ARGUMENT')
Вывод:
begin foo
FOO called with ARGUMENT
end foo
Реализация:
function printor(msg)
return function() print(msg) end
end
function print_start_end(prologue, epilogue)
assert(type(prologue) == 'function'
and type(epilogue) == 'function')
local M = {}
setmetatable(M, {
__concat = function(lhs, rhs)
assert(type(rhs) == 'function')
return function(...)
prologue()
local result = rhs(...)
epilogue()
return result
end
end;
})
return M
end
Главное достоинство такого метода — в «удобоваримом» синтаксисе без необходимости привлечения метамеханизмов.
Правда, используемый подход не позволяет пользоваться синтаксическим сахаром для объявления функций и методов, но это небольшая беда. Вот к такой записи не прикрутишь декоратор:
function bar(buzz)
print('BAR called with ' .. buzz)
end
foobar = {}
function foobar:buzz(foo)
print('foobar:buzz called with ' .. foo)
end
Один из вариантов применения такого декоратора — проверка входных и выходных параметров функции (и, шире, пред- и постусловий вообще).
Например (первое, что пришло в голову):
local string.rep =
docs
[[Returns a string that is the concatenation
of n copies of the string s.]] ..
args { 'string', optional 'number' } ..
rets { 'string' } ..
function (s, n)
n = n or 1
if n > 1 then
local t = {}
for i = 1, n do
t[i] = s
end
s = table.concat(t)
end
return s
end
Но об этом — в следующий раз.
Комментариев нет:
Отправить комментарий