英文:
How to dynamically generate functions in Lua?
问题
如果我有一个表格{field1=1,field2=0}
(0:升序,1:降序)
我想要生成一个函数:
function(x, y)
return x.field1 < y.field1 --这里0:'<',1:'>='
end
表格中的field1
和排序规则可以动态注入到函数中。
如何动态生成这段代码?
英文:
If I have a table {field1=1,field2=0}
(0: ascending order, 1: descending order)
I want to get a function:
function(x,y)
return x.field1 < y.field1 --there 0:'<',1:'>='
end
field1
in the table and the sorting rule can be injected in the function.
How to generate this code dynamically?
答案1
得分: 4
让我们谈谈不仅仅是代码生成方法!如问题中所述,考虑函数的需求:
function (x, y)
return x.field1 --[[ < or >= ]] y.field1
end
为了示例,假设我们有全局变量:
FIRST = {field1 = 3}
SECOND = {field1 = 5}
分支
我脑海中最简单的解决方案(也许是最典型的?)是一个冗长的 if
:
function foo (x, y, o)
if o == nil or o == "asc" then
return x.field1 < y.field1
end
if o == "dsc" then
return x.field1 >= y.field1
end
error("Unknown option")
end
-- 示例:
foo(FIRST, SECOND, "asc")
foo(FIRST, SECOND, "dsc")
请注意,在这种情况下,早期返回使 else
不必要,但这可能并不总是正确的。
匿名函数
但是,嘿,那是什么?如果我们传递的不是一个字符串选项,而是一些更奇怪的东西,比如...可以被调用的东西怎么办?这次我们使用一个简单的函数:
local asc = function (a, b) return a < b end
local dsc = function (a, b) return a >= b end
function bar (x, y, compare)
compare = compare or asc
return compare(x.field1, y.field1)
end
-- 示例:
bar(FIRST, SECOND, asc)
bar(FIRST, SECOND, dsc)
bar(FIRST, SECOND, function (a, b) return a < b end)
高阶函数
前面的示例在进行如此简单的操作时看起来不是那么好,但让我们以此为基础,创建一个将返回所需函数的函数:
function make (compare)
return function (x, y) return compare(x.field1, y.field1) end
end
-- 示例:
local asc = make(function (a, b) return a < b end)
local dsc = make(function (a, b) return a >= b end)
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
实际生成
现在,让我们尝试更接近代码生成的方法。Lua 提供了使用 load*
函数系列加载代码块的能力。
请注意,在 5.1 中的 load
与 5.2 或 5.3 中的 load
不同。在 5.1 中,您应该使用 loadstring
而不是 load
。
function generate (op)
return load(string.format("return function (x, y) return x.field1 %s y.field1 end", op))()
end
-- 示例:
local asc = generate("<")
local dsc = generate(">=")
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
英文:
Let's talk about more than just the code generation approach! As in the question, consider the need of a function:
function (x, y)
return x.field1 --[[ < or >= ]] y.field1
end
For the sake of the examples assume that we have global variables:
FIRST = {field1 = 3}
SECOND = {field1 = 5}
Branching
The simplest solution (perhaps also the most typical?) that comes to my mind is a verbose if
:
function foo (x, y, o)
if o == nil or o == "asc" then
return x.field1 < y.field1
end
if o == "dsc" then
return x.field1 >= y.field1
end
error("Unknown option")
end
-- Example:
foo(FIRST, SECOND, "asc")
foo(FIRST, SECOND, "dsc")
Note that early returns make else
unnecessary in this case but it might not always be true.
Anonymous function
But, hey, what's that? What if rather than a string option we pass something more bizarre like... something that can be called? Let's go with a simple function this time:
local asc = function (a, b) return a < b end
local dsc = function (a, b) return a >= b end
function bar (x, y, compare)
compare = compare or asc
return compare(x.field1, y.field1)
end
-- Example:
bar(FIRST, SECOND, asc)
bar(FIRST, SECOND, dsc)
bar(FIRST, SECOND, function (a, b) return a < b end)
Higher-order function
The previous example doesn't really look that good with a such simple operation, but let's take it as a base and let's create a function that will return us the desired function:
function make (compare)
return function (x, y) return compare(x.field1, y.field1) end
end
-- Example:
local asc = make(function (a, b) return a < b end)
local dsc = make(function (a, b) return a >= b end)
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
Actual generation
Now then, let's try something closer to code generation. Lua gives us the ability to load chunks as we go with load*
function family.
Please note that load
in 5.1 is different from load
in 5.2 or load
in 5.3. In 5.1 you want to use loadstring
instead of load
.
function generate (op)
return load(string.format("return function (x, y) return x.field1 %s y.field1 end", op))()
end
-- Example:
local asc = generate("<")
local dsc = generate(">=")
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论