Добавление _concat к числам для создания диапазонов чисел — я злюсь?

Просто в качестве случайного эксперимента я рассматриваю возможность добавления метаметода __concat() в метатаблицу number (обычно это новая метатаблица, поскольку числа по умолчанию не имеют метатаблиц?).

Идея состоит в том, что я мог бы сделать что-то вроде 3..5 и получить обратно 3, 4, 5.

Затем я мог бы иметь функцию foo(tbl, ...), которая что-то делает с несколькими индексами в таблице, и вызывать ее как foo(tbl, 3..5).

Я лаю с ума или это похоже на жизнеспособную вещь?

Набросок кода (еще не проверял):

-- get existing metatable if there is one
local m = getmetatable( 0 ) or {};

-- define our concat method
m.__concat = function( left, right )
    -- note: lua may pre-coerce numbers to strings?
    -- http://lua-users.org/lists/lua-l/2006-12/msg00482.html
    local l, r = tonumber(left), tonumber(right);

    if not l or not r then -- string concat
        return tostring(left)..tostring(right);

    else -- create number range
        if l > r then l, r = r, l end; -- smallest num first?
        local t = {};
        for i = l, r do t[#t+1] = i end;
        return (table.unpack or unpack)(t);

    end
end

-- set the metatable
setmetatable( 0, m );

Дополнительный вопрос: есть ли способ заполнить значение ... значением (чтобы устранить необходимость в таблице и распаковать в приведенном выше примере)?


person Aubergine18    schedule 23.08.2015    source источник
comment
В Lua числа всегда можно привести к строке, поэтому вычисление выражения 3 .. 5 никогда не будет включать метаметод __concat, 3 .. 5 всегда будет равно строке 35.   -  person Egor Skriptunoff    schedule 24.08.2015
comment
@EgorSkriptunoff, если только вы не определите LUA_NOCVTN2S при компиляции lua.   -  person daurnimator    schedule 24.08.2015


Ответы (1)


Ваша идея может быть реализована с помощью __call метаметода:

local mt = debug.getmetatable(0) or {}
mt.__call = function(a,b)  -- a, b - positive integer numbers
   return (('0'):rep(a-1)..('1'):rep(b-a+1)):match(('()1'):rep(b-a+1))
end
debug.setmetatable(0, mt)

-- Example:
print((3)(5))  -->  3  4  5
person Egor Skriptunoff    schedule 23.08.2015
comment
Это безумие, но мне это нравится :) Я также совершенно не понимаю, как это работает. Где номера, вызываемые для запуска __call()? Что это за колдовство передо мной?! - person Aubergine18; 24.08.2015
comment
Ах... (3)(5) как (obj)( ... ) Теперь, если бы я мог просто понять строку return... - person Aubergine18; 24.08.2015
comment
Хм, print((0)(5)) --› 1 2 3 4 5 6 - person Aubergine18; 24.08.2015
comment
Да, это работает только для положительных целых чисел. Вы можете переписать функцию, чтобы она правильно обрабатывала произвольные диапазоны чисел. - person Egor Skriptunoff; 24.08.2015