是否可以在Lua中模拟绑定?

时间:2012-06-20 10:18:15

标签: lua

给定带有一个参数的lua函数,是否可以将此参数绑定到固定值以获取不带参数的函数?

更一般地说,如何将lua函数的某些输入参数绑定到某些值?

2 个答案:

答案 0 :(得分:12)

是的,这几乎可以在任何具有一等价值功能的语言中完成。

function f1(a)
   return a+1
end

function bind(a)
   return function() return f1(a) end
end

local f2 = bind(42)
print(f2())
-- 43

此特定示例适用于特定函数和参数数量,但可以轻松扩展为使用任意函数/参数。

答案 1 :(得分:0)

我刚刚创建了一个帮助函数来执行Boost :: bind所做的事情:

  • 它处理占位符以便能够替换任何位置参数
  • 它处理nil

用法:

function_binder(base_function, placeholders_format, args...)

  • base_function(function):包装函数
  • placeholders_format(string):表示args的放置方式,每个字符代表一个参数
    • .:表示包装器中的参数
    • A:代表绑定器中的参数
    • ~:表示包装器中的所有待处理参数

请参阅以下示例以便更好地理解。

简单示例:

local function divide(a, b)
    return a / b
end

local div_by_4 = function_binder(divide, ".A", 4)
print(div_by_4(12)) -- => prints: 3

local div_12_by = function_binder(divide, "A.", 12)
print(div_12_by(4)) -- => prints: 3

您还可以使用内置函数:

local debug_print = function_binder(print, "A~", "DEBUG:")
debug_print("some logs for debug")
-- => prints: DEBUG some logs for debug

-- '~' will put all following arguments:
debug_print("some", "logs", "for", "debug")
-- => prints: DEBUG some logs for debug

你也可以制作复杂的东西:

local function stuff(...)
    print("Args: ", ...)
end

local wrapper = function_binder(stuff, ".A..AA~", "two", "five", "six")
wrapper(1, 3, 4, 7, nil, 9)
-- => prints: 1 two 3 4 five six 7 nil 9

面向对象的方式

设置

要做更多的OO,你可以使用调试库:

-- apply metatable to all function
debug.setmetatable(function()end, {
    __index = {
        bind = function_binder,
    },
})

用法

local debug_print = print:bind("A~", "DEBUG:")
debug_print("add some log")
-- => prints: DEBUG: add some log

这是function_binder代码:

local function packed_args_append(packed, nb_insert, ...)
    nb_insert = nb_insert > 0 and nb_insert or select('#', ...)

    for i = 1, nb_insert do
        packed[packed.n + 1] = select(i, ...)
        packed.n = packed.n + 1
    end
end

-- replace table.unpack as it doesn't always handle nil values correctly..
local function unpacknil(packed)
    local nb_args = packed.n

    local function unpack_n(n)
        if n == nb_args then
            return packed[n]
        end
        return packed[n], unpack_n(n + 1)
    end
    return unpack_n(1)
end

function function_binder(self, placeholder_format, ...)
    local placeholders = table.pack(...)

    return function(...)
        local args = {n = 0}
        local arg_idx = 1
        local placeholder_idx = 1


        for c in placeholder_format:gmatch"." do
            if c == 'A' then
                packed_args_append(args, 1, placeholders[placeholder_idx])
                placeholder_idx = placeholder_idx + 1
            elseif c == '.' then
                packed_args_append(args, 1, select(arg_idx, ...))
                arg_idx = arg_idx + 1
            elseif c == '~' then
                packed_args_append(args, -1, select(arg_idx, ...))
                break
            end
        end
        --return self(table.unpack(args))
        return self(unpacknil(args))
    end
end

它与Lua 5.3完美配合

在此托管:https://github.com/Bew78LesellB/luaMiscTests/commit/e9e52aea7933b58332fff36738356f18aed3db92