Function 是否可以在不生成单个函数的情况下生成一个正在折叠的变量?
我有一个代码,它从少量变量开始,并使用这些初始变量生成更多元素Function 是否可以在不生成单个函数的情况下生成一个正在折叠的变量?,function,variables,lua,Function,Variables,Lua,我有一个代码,它从少量变量开始,并使用这些初始变量生成更多元素 function new( x, y, width, height ) local object = {} --border object.border = { x = x, y = y, width = width, height = height } --body object.body = { x = x+1, y = y+1, width = width-2, height = hei
function new( x, y, width, height )
local object = {}
--border
object.border = { x = x, y = y, width = width, height = height }
--body
object.body = { x = x+1, y = y+1, width = width-2, height = height-2 }
--font
object.font = {}
object.font.size = (object.body.height+2)-(math.floor((object.body.height+2)/4)+1)
object.font.height = love.graphics.setNewFont( object.font.size ):getHeight()
--padding
object.padding = {}
object.padding.height = math.floor(object.border.height*(2/29))
object.padding.width = object.padding.height*3
--text
object.text = { input = '' }
object.text.centerHeight = math.ceil(object.body.y+((object.body.height-object.font.height)/2))
object.text.left = object.body.x+object.padding.width+object.padding.height
--backspacing
object.backspace = {key = false, rate = 3, time = 0, pausetime = 20, pause = true}
--config
object.config = { active = true, devmode = false, debug = false, id = gui.id(), type = 'textbox' }
gui.add(object)
return object.config.id
end
当我修改中间部分时,整个事情变得混乱,因为从一开始我改变了,直到底部的值彼此不一致
local x = gui.get(2)
x.body.height = 50
我在寻找是否有一种方法可以重新定义这些变量,从它们开始到底部,而不:(a)为每个变量生成函数。和(b)编辑功能中所需的参数
如果没有,这是一种有效的替代方法吗
编辑:
变量的结构如下所示:
border->body->padding->font
我需要的是一种方法,我可以定义它们中的任何一个,这样下面的一个也会发生如下变化:
object.body.x = 15
它将从重新定义的变量崩溃到底部:
body->padding->font
我可以从编辑的变量重新定义它们,直到底部,如下所示:
--not the actual code, just an example of variables dependent on the variable above
object.body.x = 15
object.padding.width = object.body.x+1
object.font.size = object.padding.width+1
但这意味着我在重新定义填充时也必须这样做,直到字体变得非常低效,尤其是当我扩展了更多元素时
例如:
--padding->font
object.padding.width = 5
object.font.size = object.padding.width+1
您可以使用元表,更具体地说是uu newindex字段: (好吧,需要将它与_索引字段组合,但是呃) 您可以运行类似于
proxy.x=12的代码来编辑x属性。将重新计算所有值。这不是最好的,但是你的代码需要改进。(但嘿,如果它对你有用,那就好了)
注意:只能设置x、y、宽度和高度。但是,您可以使用旧方法获取所有属性,例如proxy.padding.width(请注意proxy.x不起作用。请使用proxy.border.x)我很无聊,看到了这个问题(再次)和一个重复的问题。
我开始写一些有趣的代码,结果是:
local function getNeededVars(tab,func)
local needed,this = {}
this = setmetatable({},{
__index = function(s,k)
-- See if the requested variable exists.
-- If it doesn't, we obviously complain.
-- If it does, we log it and return the value.
local var = tab.vars[k]
if not var then
error("Eh, "..k.." isn't registered (yet?)",5)
end needed[k] = true return tab.vals[k]
end;
}) func(this) return needed
end
local function updateStuff(self,key,done)
for k,v in pairs(self.levars) do
if v.needed and v.needed[key] then
if not done[v] then done[v] = true
self.vals[v.name] = v.func(self)
updateStuff(self,v.name,done)
end
end
end
end
local function createSubTable(self,key,tab)
return setmetatable({},{
__newindex = function(s,k,v)
tab[k] = v updateStuff(self,key,{})
end; __index = tab;
})
end
local dependenceMeta
dependenceMeta = {
__index = function(self,k)
-- Allow methods, because OOP
local method = dependenceMeta[k]
if method then return method end
local variable = self.vars[k]
if not variable then
error("Variable "..k.." not found",2)
end return self.vals[k]
end;
__newindex = function(self,k,v)
local variable = self.vars[k]
if not variable then
error("Use :Register() to add stuff",2)
elseif type(v) == "table" then
self.vals[k] = createSubTable(self,k,v)
return updateStuff(self,k,{})
end self.vals[k] = v updateStuff(self,k,{})
end
}
function dependenceMeta:Register(var,value)
local varobject = {func=value,name=var}
self.vars[var] = varobject
table.insert(self.levars,varobject)
if type(value) == "function" then
varobject.needed = getNeededVars(self,value)
self.vals[var] = value(self)
elseif type(value) == "table" then
self.vals[var] = createSubTable(self,var,value)
elseif value then
self.vals[var] = value
end
end
function dependenceMeta:RegisterAll(tab)
for k,v in pairs(tab) do
self:Register(k,v)
end
end
local function DependenceTable()
return setmetatable({
levars = {};
vars = {};
vals = {};
},dependenceMeta)
end
local test = DependenceTable()
test:Register("border",{
x=20; y=50;
height=200;
width=100;
})
test:Register("body",function(self)
return {x=self.border.x+1,y=self.border.y+1,
height=self.border.height-2,
width=self.border.width-2}
end)
test:Register("font",function(self)
local size = (self.body.height+2)-(math.floor((self.body.height+2)/4)+1);
return { size = size; -- Since we use it in the table constructor...
height = size-4; --love.graphics.setNewFont( self.font.size ):getHeight();
-- I don't run this on love, so can't use the above line. Should work though.
}
end)
test:Register("padding",function(self)
local height = math.floor(self.border.height*(2/29))
return { height = height; width = height*3 } -- again dependency
end)
test:Register("text",{input=""}) -- Need this initially to keep input
test:Register("text",function(self)
return { input = self.text.input;
centerHeight = math.ceil(self.body.y+((self.body.height-self.font.height)/2));
left = self.body.x+self.padding.width+self.padding.height;
}
end)
test:Register("backspace",{key = false, rate = 3, time = 0, pausetime = 20, pause = true})
-- Again, didn't use gui.id() on the line below because my lack of LÖVE
test:Register("config",{active=true,devmode=false,debug=false,id=123,type='textbox'})
print("border.x=20, test.text.left="..test.text.left)
test.border = {x=30; y=50; height=200; width=100;}
print("border.x=30, test.text.left="..test.text.left)
test.border.x = 40
print("border.x=40, test.text.left="..test.text.left)
代码很多,但我喜欢写。它提供了很好的输出:
border.x=20, test.text.left=73
border.x=30, test.text.left=83
border.x=40, test.text.left=93
所有属性只有在编辑其中一个依赖项时才会重新计算。我让它也能与子表一起工作,这有点棘手,但最后看起来其实很容易。例如,可以通过将body字段设置为全新的表或在现有表中设置字段来编辑body字段,如代码段的最后几行所示。当您将其分配给新表时,它将在其上设置一个元表。您也不能使用pairs(&co),除非您使用5.2并且可以使用_pairs
这可能会解决你的问题。如果不是的话,我写这篇文章很开心,所以至少我写这篇文章总是有积极意义的。(你必须承认,这是一些漂亮的代码。好吧,它的工作方式,而不是实际的格式)
注意:如果要使用它,请取消对love.graphics和gui.id部分的注释,因为我没有LÖVE,显然我必须测试代码
下面是我的东西的API的一个快速“摘要”,因为一开始可能会让人困惑:
local hmm = DependenceTable() -- Create a new one
print(hmm.field) -- Would error, "field" doesn't exist yet
-- Sets the property 'idk' to 123.
-- Everything except functions and tables are "primitive".
-- They're like constants, they never change unless you do it.
hmm:Register("idk",123)
-- If you want to actually set a regular table/function, you
-- can register a random value, then do hmm.idk = func/table
-- (the "constructor registering" only happens during :Register())
-- Sets the field to a constructor, which first gets validated.
-- During registering, the constructor is already called once.
-- Afterwards, it'll get called when it has to update.
-- (Whenever 'idk' changes, since 'field' depends on 'idk' here)
hmm:Register("field",function(self) return self.idk+1 end)
-- This errors because 'nonexistant' isn't reigstered yet
hmm:Register("error",function(self) return self.nonexistant end)
-- Basicly calls hmm:Register() twice with key/value as parameters
hmm:RegisterAll{
lower = function(self) return self.field - 5 end;
higher = function(self) return self.field + 5 end;
}
-- This sets the property 'idk' to 5.
-- Since 'field' depends on this property, it'll also update.
-- Since 'lower' and 'higher' depend on 'field', they too.
-- (It happens in order, so there should be no conflicts)
hmm.idk = 5
-- This prints 6 since 'idk' is 5 and 'field' is idk+1
print(hmm.field)
您可以使用setfenv(如果lua5.1)来删除“self.FIELD”的需要。通过一些环境魔法,您可以使用“field”的构造函数(例如)只要是function()return idk+1 end
这里不清楚您的意思。什么样的修改“在中间部分”导致事情“变得一团糟”。给我们举个例子。@NicolBolas我在底部给出了一个例子,我所有的变量都存储在一个本地文件中,并使用gui.get()和gui.add()等来访问。我的意思是在中间部分是当我改变Boy.Load元素时,我也想改变TeX.Lead元素,因为它也使用Boy.Load定义。有点像多米诺效应,当你影响某事物,但只在一个方向而不是一切时崩溃。你可以使用“y-NeWDEX”和“代理表”……我只需要GOTO在C++中如何工作,但在Lua中不可用,我需要做一个函数,从变量到底部编辑VAR,(对于每个动态变量).1个长函数,用于重新定义动态变量,因此底部的变量也会发生变化,这是非常不切实际的。我希望有人能提供帮助。重新定义x/w/宽度/高度是我的最小问题,因为我可以使用我想要给出的新值来回忆原始函数。然后替换存储该函数的表中的整个索引。
local hmm = DependenceTable() -- Create a new one
print(hmm.field) -- Would error, "field" doesn't exist yet
-- Sets the property 'idk' to 123.
-- Everything except functions and tables are "primitive".
-- They're like constants, they never change unless you do it.
hmm:Register("idk",123)
-- If you want to actually set a regular table/function, you
-- can register a random value, then do hmm.idk = func/table
-- (the "constructor registering" only happens during :Register())
-- Sets the field to a constructor, which first gets validated.
-- During registering, the constructor is already called once.
-- Afterwards, it'll get called when it has to update.
-- (Whenever 'idk' changes, since 'field' depends on 'idk' here)
hmm:Register("field",function(self) return self.idk+1 end)
-- This errors because 'nonexistant' isn't reigstered yet
hmm:Register("error",function(self) return self.nonexistant end)
-- Basicly calls hmm:Register() twice with key/value as parameters
hmm:RegisterAll{
lower = function(self) return self.field - 5 end;
higher = function(self) return self.field + 5 end;
}
-- This sets the property 'idk' to 5.
-- Since 'field' depends on this property, it'll also update.
-- Since 'lower' and 'higher' depend on 'field', they too.
-- (It happens in order, so there should be no conflicts)
hmm.idk = 5
-- This prints 6 since 'idk' is 5 and 'field' is idk+1
print(hmm.field)