7

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

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

4

2 回答 2

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

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

于 2012-06-20T11:42:16.247 回答
1

我刚刚创建了一个辅助函数来执行 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

面向对象的方式

设置

要做更多的面向对象的东西,你可以使用调试库:

-- 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

于 2016-09-01T14:30:15.053 回答