是否可以在不制作单个函数的情况下创建折叠变量? [英] Is it possible to make a collapsing variables without making individual functions?

查看:118
本文介绍了是否可以在不制作单个函数的情况下创建折叠变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 功能新增功能新增功能(x,y,width,height)
本地对象= {}
--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.body.height-object.font.height)/ 2))
object.text.left = object.body.x + obje ct.padding.width + object.padding.height
--backspacking
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 

我可以重新定义他们从编辑的变量,直到像这样的底部:

   - 不是实际的代码,只是一个例子变量依赖于
以上的变量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


解决方案

I感到无聊,并且看到这个问题(再次)以及重复。
我开始编写一些有趣的代码,导致这个:

$ p $ local $ getNeededVars(tab,func) $ b本地需要,this = {}
this = setmetatable({},{
__index = function(s,k)
- 查看请求变量是否存在
- 如果没有,我们显然会抱怨。
- 如果是这样,我们会记录它并返回值
local var = tab.vars [k]
如果不是var那么
错误(Eh,..k ..未注册(尚未?),5)
需要结尾[k] =真正返回tab.vals [k]
);
})func(this)返回所需
结束

本地函数updateStuff(self,key,done)
for k,v in pairs(self .levars)做
如果v.needed和v.needed [key]然后
如果没做完[v]然后done [v] = true
self.vals [v.name] = v.func(self)
updateStuff(self,v.name,done)
end
结束
结束
结束

本地函数createSubTable(self,key,tab)
返回setmetatable({},{
__newindex = function(s, k,v)
tab [k] = v updateStuff(self,key,{})
end; __index = tab;
})
结束

本地依赖关系Meta
dependenceMeta = {
__index = function(self,k)
- 允许使用方法,因为OOP
local method = dependenceMeta [k]
if method then return method
local variable = self.vars [k]
if not variable then
error(变量..k ..未找到,2)
结束返回self.vals [k]
结束;
__newindex =函数(self,k,v)
局部变量= self.vars [k]
如果不是变量,则
错误(Use:Register() ,2)
elseif type(v)==tablethen
self.vals [k] = createSubTable(self,k,v)
return updateStuff(self,k,{ })
end self.vals [k] = v updateStuff(self,k,{})
end
}
函数dependenceMeta:Register(var,value)
local varobject = {func = value,name = var}
self.vars [var] = varobject
table.insert(self.levars,varobject)
if type(value)== functionthen
varobject.needed = getNeededVars(self,value)
self.vals [var] = value(self)
elseif type(value)==tablethen
self.vals [var] = createSubTable(self,var,value)
elseif value then
self.vals [var] = value
end
end
函数dependenceMeta:RegisterAll(tab)
for k,v成对(tab)do
self:Register(k,v)
end
end

本地函数DependenceTable()
返回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; - 由于我们在表构造函数中使用它...
height = size-4; --love.graphics.setNewFont(self.font.size) :getHeight();
- 我不会在爱情上运行这个,所以不能使用上面的代码,应该可以工作
}
end)
test: Register(padding,function(self)
local height = math.floor(self.border.height *(2/29))
return {height = height; width = height * 3} - - 再次依赖
结束)
test:Register(text,{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})
- - 再一次,因为我缺少LÖVE
test,所以没有在下面一行使用gui.id():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;高度= 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 字段,方法是将其设置为全新的表格或在现有表格中设置字段,如最后几行所示的代码片段。当你将它分配给一个新表时,它会设置一个metatable。你不能使用对(& co),除非你使用5.2并且可以使用__pairs。



它可以解决你的问题。如果不是的话,我很乐意写它,所以至少我写这篇文章总是积极的。 (你不得不承认,这是一些漂亮的代码,嗯,它的工作方式,不是实际的格式)
$ b 注意:如果您要使用它,请取消 love.graphics gui.id 部分的注释,因为我没有LÖVE,我显然必须测试代码。



以下是我的API的快速汇总,因为它可能会在开始时引起混淆:

  local hmm = DependenceTable() - 创建一个新的
print(hmm.field) - 会出错,字段还不存在

- 将属性'idk'设置为123.
- 除函数和表之外的所有内容都是原始的。
- 它们就像常量,除非你这么做,否则它们永远不会改变。
hmm:Register(idk,123)
- 如果你想真正设置一个常规表/函数,你
- 可以注册一个随机值,然后执行hmm.idk = func / table
- (构造函数注册只发生在:Register())

- 将该字段设置为一个构造函数,该构造函数首先得到验证。
- 在注册过程中,构造函数已被调用一次。
- 之后,它将在需要更新时被调用。
- (每当'idk'改变时,'field'取决于'idk')
hmm:Register(field,function(self)return self.idk + 1 end)
- 这个错误是因为'nonexistant'还没有被reigstered而已
hmm:Register(error,function(self)return self.nonexistant end)
- 基本调用hmm:Register()键/值作为参数两次
hmm:RegisterAll {
lower = function(self)return self.field - 5 end;
higher = function(self)return self.field + 5 end;
}
- 将属性'idk'设置为5.
- 由于'field'取决于此属性,因此它也会更新。
- 由于更低和更高取决于字段,所以也是如此。
- (它是按顺序发生的,所以不应该有冲突)
hmm.idk = 5
- 由于'idk'是5,'field'是idk + 1
print(hmm.field)

你可以使用setfenv(如果Lua 5.1)删除'self.FIELD'的需要。使用一些环境魔法,你可以使用'field'的构造函数(作为一个例子)就是 function()return idk + 1 end / p>

I have a code that starts as a small amount of variables and makes more elements using those initial variables.

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

and when I modify something in the middle part, the whole thing becomes a mess because starting from the one i changed until the bottom ones value doesn't agree with each other

local x = gui.get(2)
x.body.height = 50

I'm looking if there's a way for these variables to be redefined, starting from them until the bottom, without: (a) making functions for each of the variables. and (b) editing the required parameters in the function.

and If there's none, are the an alternate way to do this efficiently?

EDIT: the structure of the variables is as follow:

border->body->padding->font

what i needed is a way i can define any of them so that the one that follows also changes like:

object.body.x = 15

and it would collapse from that redefined variable until the bottom:

body->padding->font

i could just redefine them from the edited variable until the bottom like this:

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

but that means I have to do the same when redefining the padding until the font which is extremely inefficient especially when I extended more elements.

example:

--padding->font
object.padding.width = 5
object.font.size = object.padding.width+1

解决方案

I was bored and saw this question (again) along with a duplicate. I started writing some code for fun, leading to this:

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)

It's a lot of code, but I liked writing it. It gives this nice output:

border.x=20, test.text.left=73
border.x=30, test.text.left=83
border.x=40, test.text.left=93

All properties only get recalculated when one of its dependencies is edited. I made it also work with subtables, which was a bit tricky, but at the end actually seems quite easy. You can edit (for example) the body field by setting it to a completely new table or by setting a field in the already existing table, as seen in the last few lines of the code snippet. When you assign it to a new table, it'll set a metatable on it. You can't use pairs (& co) neither, unless you use 5.2 and can use __pairs.

It might solve your problem. If not, I had fun writing it, so at least it'll always be something positive that I wrote this. (And you have to admit, that's some beautiful code. Well, the way it works, not the actual formatting)

Note: If you're gonna use it, uncomment the love.graphics and gui.id part, as I don't have LÖVE and I obviously had to test the code.

Here's a quick "summary" of my thing's API, as it might be confusing in the beginning:

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)

You could use setfenv (if Lua 5.1) to remove the need of 'self.FIELD'. With some environment magic you can have the constructor for 'field' (as an example) just be function() return idk+1 end.

这篇关于是否可以在不制作单个函数的情况下创建折叠变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆