2016-10-06 2 views
3

속성 선언에 대한 자동 지원을 추가하여 클래스에 자동으로 생성되는 getter 및 setter를 가져옵니다. 중간 클래스 라이브러리를 클래스의 기반으로 사용합니다. 속성 생성을 처리하는 루트 클래스를 정의했습니다. 그러나 테스트에서 루트 클래스의 바로 하위 클래스 만 제대로 작동합니다. 다른 날 중산층 코드 깊은 스택 오버플로 오류 ([string "local middleclass = {..."]:82: stack overflow) 줄.middleclass : 속성에 대한 getter-setter 지원 추가

내 코드는 다음과 같습니다

local CBaseObject=class('CObjectBase'); 
function CBaseObject:initialize() 
    self._init=true; 
end; 
function CBaseObject:finalize() 
    self._init=false; 
end; 
function CBaseObject:_getter_setter(v) 
    return v; 
end; 
function CBaseObject:_gen_prop_cache() 
    rawset(self,'_properties',rawget(self,'_properties') or {}); 
end; 
function CBaseObject:__index(k) 
    print('GET',k); 
    self:_gen_prop_cache(); 
    local prop=self._properties[k]; 
    if prop~=nil 
    then 
     local getter=self[prop[2] or '_getter_setter']; 
     return getter(self,prop[1]); 
    else return nil;end; 
end; 
function CBaseObject:__newindex(k,v) 
    print('ME',self.class.name); 
    print('SET',k,v); 
    self:_gen_prop_cache(); 
    local prop=self._properties[k]; 
    if prop==nil and self._init or prop 
    then 
     if prop==nil then prop={};self._properties[k]=prop;end; 
     local vv=prop[1]; 
     if type(v)=='table' and #v<4 
     then 
      for i=1,3 do prop[i]=v[i];end; 
     else 
      prop[1]=v; 
     end; 
     local setter=self[prop[3] or '_getter_setter']; 
     prop[1]=setter(self,prop[1],vv); 
    else 
     rawset(self,k,v); 
    end; 
end; 

테스트 클래스 :

local cls=CBaseObject:subclass('test'); 
function cls:initialize() 
    self.class.super.initialize(self); 
    self.health={1000,'_gethealth','_sethealth'}; 
    self.ammo=100; 
    self:finalize(); 
end; 
function cls:_sethealth(value,old) 
    print('WRITE:',value,old); 
    if value<0 then return old;else return value;end; 
end; 
function cls:_gethealth(value) 
    print('READ:',value); 
    return value/1000; 
end; 

local cls2=cls:subclass('test2'); 
function cls2:initialize() 
    self.class.super.initialize(self); 
    self.ammo=200; 
    self:finalize(); 
end; 
function cls2:_sethealth(value,old) 
    print('WRITE_OVERRIDEN:',value,old); 
    return value; 
end; 
local obj=cls2(); --change this to cls() for working example. 
obj.health=100; 
obj.health=-100; 
print(obj.health,obj._properties.health[1]); 
print(obj.ammo,obj._properties.ammo[1]); 

내 코드를 실행 https://repl.it/languages/lua을 사용했다. 그래서, 질문은, 내가 옳은 방법으로하는 것입니까? 사용 된 라이브러리와 호환되는 더 쉬운 방법으로 속성 지원을 추가 할 수 있습니까? 아니면 다른 것을 사용해야합니까?

편집 : 실험 후 나는 구조상 self.class.parent.<method>(<...>)이 오류에 대한 책임이 있다는 것을 알아 냈습니다. 나는 그러한 모든 사건을 실제 부모 클래스로 바꿨다. 그게 유일한 문제 였고, 그 후 코드는 지금까지 오류없이 작동하기 시작했습니다.

+0

질문에 직접 답변하거나 대답하거나 질문을 수정할 수없는 경우 ...당신은 thits 세미콜론 btw를 제거 할 수 있습니다. 그들은 루아에서 필요하지 않습니다. – Piglet

+0

그러나 나는 아직도 내가 한 일을 잘 할 수 없다는 것을 확신하지 못한다. 세미콜론은 다른 언어로 습관을 버리고 싶지 않기 때문에 필자는 세미콜론을 사용합니다. 기본적으로 모든 언어가 필요합니다. – ZzZombo

답변

1

엔리케 가르시아 코타 (middleclass 작성자)는 중산층에 좋은 way to implement getters/setters이라고 생각되는 것을 나에게 밝혀주었습니다. 그는 mixin을 만들고 사용하도록 제안했습니다.

이 믹스 인 레시피를 테스트/사용하는 동안 약간의 변경을했습니다. 나는이 같은 외모를 사용하고 현재 하나 :

-- properties.lua 
local Properties = {} 

function Properties:__index(k) 
    local getter = self.class.__instanceDict["get_" .. k] 
    if getter ~= nil then 
     return getter(self) 
    end 
end 

function Properties:__newindex(k, v) 
    local setter = self["set_" .. k] 
    if setter ~= nil then 
     setter(self, v) 
    else 
     rawset(self, k, v) 
    end 
end 

return Properties 

당신은 당신의 속성에 대한 function get_ * 및 function set_ *을 생성 (또는 당신이 원하는대로 위의 문자열 패턴을 수정)해야합니다.

예 : 당신이 그것을에 get_ * 및 set_ * 함수를 만들 단순히 속성을 가지고 원하는 클래스에서이 믹스 인을 사용할 수 있습니다

local class = require('middleclass') 
local Properties = require('properties') 

local Rect = class('Rect'):include(Properties) 

function Rect:initialize(x, y, w, h) 
    self.x = x 
    self.y = y 
    self.w = w 
    self.h = h 
end 

function Rect:get_right() 
    return self.x + self.w 
end 

function Rect:set_right(right) 
    self.x = self.x + right - self.right 
end 

r = Rect:new(10,10, 100, 100) 

print(r.right) -- 110 
print(r:get_right()) -- 110 
r.right = 200 
print(r.right) -- 200 
print(r.x) -- 100 

이 방법.

그는 또한 그러나, 말했다 :

내가 루아에서 게터/세터의 열렬한 팬이 아니다. 다른 언어들도 받아 들일 수 있습니다. 예를 들어 루비에서는 언어의 메시지 전달 메커니즘에 통합되어 있습니다.

루아에서 그들은 구문론적인 여분의 설탕이며, "마법"(코드에 익숙하지 않은 사람에게는 예기치 않은)을 만드는 위험이 있습니다.

성능 주 : 그것은 (__index 테이블과 비교하는 경우)의 예처럼, __index 기능을 사용하면, 코드의 성능에 크게 영향을해야 않습니다, 그러나, 언급 할 가치가있다. 개인적으로 getter 및 setter를 사용하여 (Python 편향으로 인해) 얼마 후 필자는 명시 적으로 작성하고 더 이상 의존하지 않습니다. 코드에 따라 성능이 중요한지 아닌지에 따라 다릅니다.

관련 문제