2016-10-06 3 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を使用しました。それで、質問は、私が正しいアプローチでさえもやっていることですか?使用しているライブラリと互換性のある簡単な方法でプロパティサポートを追加することは可能ですか?それとも、私は別のものを使うべきですか?

EDIT:実験した後、私は構造体self.class.parent.<method>(<...>)がエラーの原因であることを知りました。私はそのような出来事をすべて実際の親クラスで置き換えました。これが唯一の問題でした。それ以降、コードはこれまでのところエラーフリーで動作するようになりました。

+0

あなた自身であなたの質問に答えることができます、それに答える、質問を編集しないでください...あなたはセミコロンbtwを削除することができます。彼らはLuaでは必要ではありません。 – 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 

この方法です。

彼はまた、しかし、言った:

を私はLuaのでゲッター/セッターの巨大なファンではありません。他の言語でも、私はそれを受け入れることができます。例えば、ルビでは、言語のメッセージ・パッシング・メカニズムに組み込まれています。

しかし、ルアでは構文上の余分な砂糖があり、コードをよく知らない人にとっては「魔法のようなもの」になる危険性があります。

パフォーマンスノート:それは(__indexテーブルに比べた場合)の例のように、__index機能を使用すると、あなたのコードのパフォーマンスに大きく影響を与えるべきではないこと、しかし、言及する価値があります。 個人的には、(私のPythonのバイアスのために)ゲッターとセッターを使ってしばらくしてから、明示的に書くことに決めたので、もはやそれらに依存しなくなりました。 あなたのコードでは、パフォーマンスが重要であるかどうかによって異なります。

関連する問題