2009-07-07 13 views
6

मुझे Lua में कक्षाओं को कठिन समय मिल रहा है। फलहीन गुगल ने मुझे मेटा-टेबल के बारे में विचारों का नेतृत्व किया, और बताया कि कक्षाओं को अनुकरण/लिखने के लिए तीसरे पक्ष के पुस्तकालयों को आवश्यक है।लुआ में कक्षा, उप-वर्ग और संपत्ति कैसे बनाएं?

यहां एक नमूना है (सिर्फ इसलिए कि मैंने देखा है मैं बेहतर जवाब पाने जब मैं नमूना कोड प्रदान करते हैं):

public class ElectronicDevice 
{ 
    protected bool _isOn; 
    public bool IsOn { get { return _isOn; } set { _isOn = value; } } 
    public void Reboot(){_isOn = false; ResetHardware();_isOn = true; } 
} 

public class Router : ElectronicDevice 
{ 
} 

public class Modem :ElectronicDevice 
{ 
    public void WarDialNeighborhood(string areaCode) 
    { 
     ElectronicDevice cisco = new Router(); 
     cisco.Reboot(); 
     Reboot(); 
     if (_isOn) 
      StartDialing(areaCode); 
    } 
} 

यहाँ मेरी पहली तकनीक जेवियर ने सुझाव दिया उपयोग करके उपरोक्त अनुवाद करने के लिए प्रयास है।

मैंने आरबीरटेग की सलाह ली। हालांकि, व्युत्पन्न वर्ग पर आमंत्रण अभी भी उपज: "attempt to call method 'methodName' (a nil value)"

--Everything is a table 
ElectronicDevice = {}; 

--Magic happens 
mt = {__index=ElectronicDevice}; 

--This must be a constructor 
function ElectronicDeviceFactory() 
    -- Seems that the metatable holds the fields 
    return setmetatable ({isOn=true}, mt) 
end 

-- Simulate properties with get/set functions 
function ElectronicDevice:getIsOn() return self.isOn end 
function ElectronicDevice:setIsOn(value) self.isOn = value end 
function ElectronicDevice:Reboot() self.isOn = false; 
    self:ResetHardware(); self.isOn = true; end 
function ElectronicDevice:ResetHardware() print('resetting hardware...') end 

Router = {}; 
mt_for_router = {__index=Router} 

--Router inherits from ElectronicDevice 
Router = setmetatable({},{__index=ElectronicDevice}); 

--Constructor for subclass, not sure if metatable is supposed to be different 
function RouterFactory() 
    return setmetatable ({},mt_for_router) 
end 

Modem ={}; 
mt_for_modem = {__index=Modem} 

--Modem inherits from ElectronicDevice 
Modem = setmetatable({},{__index=ElectronicDevice}); 

--Constructor for subclass, not sure if metatable is supposed to be different 
function ModemFactory() 
    return setmetatable ({},mt_for_modem) 
end 

function Modem:WarDialNeighborhood(areaCode) 
     cisco = RouterFactory(); 
     --polymorphism 
     cisco.Reboot(); --Call reboot on a router 
     self.Reboot(); --Call reboot on a modem 
     if (self.isOn) then self:StartDialing(areaCode) end; 
end 

function Modem:StartDialing(areaCode) 
    print('now dialing all numbers in ' .. areaCode); 
end 

testDevice = ElectronicDeviceFactory(); 
print("The device is on? " .. (testDevice:getIsOn() and "yes" or "no")); 
testDevice:Reboot(); --Ok 

testRouter = RouterFactory(); 
testRouter:ResetHardware(); -- nil value 

testModem = ModemFactory(); 
testModem:StartDialing('123'); -- nil value 
+0

क्या आपने [यह] पढ़ा था (http://lua-users.org/wiki/SimpleLuaClasses)? – ThibThib

+0

हाँ और मैंने इसे अपारदर्शी पाया। – MatthewMartin

उत्तर

8

यहां एक उपयोगी Class लाइब्रेरी के साथ आपके कोड का शाब्दिक प्रतिलेखन उदाहरण है जिसे किसी अन्य फ़ाइल में स्थानांतरित किया जा सकता है।

यह Class का एक वैधानिक कार्यान्वयन नहीं है; हालांकि आप अपने ऑब्जेक्ट मॉडल को परिभाषित करने के लिए स्वतंत्र महसूस करें।

Class = {} 

function Class:new(super) 
    local class, metatable, properties = {}, {}, {} 
    class.metatable = metatable 
    class.properties = properties 

    function metatable:__index(key) 
     local prop = properties[key] 
     if prop then 
      return prop.get(self) 
     elseif class[key] ~= nil then 
      return class[key] 
     elseif super then 
      return super.metatable.__index(self, key) 
     else 
      return nil 
     end 
    end 

    function metatable:__newindex(key, value) 
     local prop = properties[key] 
     if prop then 
      return prop.set(self, value) 
     elseif super then 
      return super.metatable.__newindex(self, key, value) 
     else 
      rawset(self, key, value) 
     end 
    end 

    function class:new(...) 
     local obj = setmetatable({}, self.metatable) 
     if obj.__new then 
      obj:__new(...) 
     end 
     return obj 
    end 

    return class 
end 

ElectronicDevice = Class:new() 

function ElectronicDevice:__new() 
    self.isOn = false 
end 

ElectronicDevice.properties.isOn = {} 
function ElectronicDevice.properties.isOn:get() 
    return self._isOn 
end 
function ElectronicDevice.properties.isOn:set(value) 
    self._isOn = value 
end 

function ElectronicDevice:Reboot() 
    self._isOn = false 
    self:ResetHardware() 
    self._isOn = true 
end 

Router = Class:new(ElectronicDevice) 

Modem = Class:new(ElectronicDevice) 

function Modem:WarDialNeighborhood(areaCode) 
    local cisco = Router:new() 
    cisco:Reboot() 
    self:Reboot() 
    if self._isOn then 
     self:StartDialing(areaCode) 
    end 
end 

आप पाने के लिए/संपत्तियों के लिए सेट तरीकों रहना हो तो आप __index और __newindex कार्यों की जरूरत नहीं होगी, और सिर्फ एक __index मेज हो सकता था। उस मामले में, सबसे आसान तरीका विरासत अनुकरण करने के लिए कुछ इस तरह है:

BaseClass = {} 
BaseClass.index = {} 
BaseClass.metatable = {__index = BaseClass.index} 

DerivedClass = {} 
DerivedClass.index = setmetatable({}, {__index = BaseClass.index}) 
DerivedClass.metatable = {__index = DerivedClass.index} 

दूसरे शब्दों में, व्युत्पन्न वर्ग के __index तालिका "विरासत" आधार वर्ग के __index तालिका।यह काम करता है क्योंकि लुआ, __index तालिका में प्रतिनिधि होने पर प्रभावी रूप से उस पर लुकअप को दोहराता है, इसलिए __index तालिका के मेटामॉइड का आह्वान किया जाता है।

इसके अलावा, obj.Method(...) बनाम obj:Method(...) बुला के बारे में सावधान रहना। obj:Method(...)obj.Method(obj, ...) के लिए वाक्य रचनात्मक चीनी है, और दो कॉलों को मिलाकर असामान्य त्रुटियां उत्पन्न हो सकती हैं।

6

तरीकों से आप यह कर सकते हैं की एक संख्या हैं, लेकिन यह मैं कैसे (विरासत में एक शॉट के साथ अद्यतन) है:

function newRGB(r, g, b) 
    local rgb={ 
     red = r; 
     green = g; 
     blue = b; 
     setRed = function(self, r) 
      self.red = r; 
     end; 
     setGreen = function(self, g) 
      self.green= g; 
     end; 
     setBlue = function(self, b) 
      self.blue= b; 
     end; 
     show = function(self) 
      print("red=",self.red," blue=",self.blue," green=",self.green); 
     end; 
    } 
    return rgb; 
end 

purple = newRGB(128, 0, 128); 
purple:show(); 
purple:setRed(180); 
purple:show(); 

---// Does this count as inheritance? 
function newNamedRGB(name, r, g, b) 
    local nrgb = newRGB(r, g, b); 
    nrgb.__index = nrgb; ---// who is self? 
    nrgb.setName = function(self, n) 
     self.name = n; 
    end; 
    nrgb.show = function(self) 
     print(name,": red=",self.red," blue=",self.blue," green=",self.green); 
    end; 
    return nrgb; 
end 

orange = newNamedRGB("orange", 180, 180, 0); 
orange:show(); 
orange:setGreen(128); 
orange:show(); 

मैं निजी, संरक्षित, आदि लागू नहीं करें although it is possible

1

लुआ में कक्षा-जैसे ओओपी करना वास्तव में आसान है; व्यक्तिगत रूप से, मैं कभी नहीं की जरूरत की है विरासत

local myClassMethods = {} 
local my_mt = {__index=myClassMethods} 

function myClassMethods:func1 (x, y) 
    -- Do anything 
    self.x = x + y 
    self.y = y - x 
end 

............ 

function myClass() 
    return setmetatable ({x=0,y=0}, my_mt) 

, इसलिए ऊपर मेरे लिए काफी है: बस एक metatable की __index क्षेत्र में सभी 'तरीकों' रख दिया। यदि यह पर्याप्त नहीं है, तो आप तरीकों तालिका के लिए एक metatable सेट कर सकते हैं:

local mySubClassMethods = setmetatable ({}, {__index=myClassMethods}) 
local my_mt = {__index=mySubClassMethods} 

function mySubClassMethods:func2 (....) 
    -- Whatever 
end 

function mySubClass() 
    return setmetatable ({....}, my_mt) 

अद्यतन: अपने अपडेट किए गए कोड में कोई त्रुटि है:

Router = {}; 
mt_for_router = {__index=Router} 
--Router inherits from ElectronicDevice 
Router = setmetatable({},{__index=ElectronicDevice}); 

ध्यान दें कि आप Router प्रारंभ, और निर्माण इस से mt_for_router; लेकिन फिर आप Router को एक नई तालिका में फिर से सौंपें, जबकि mt_for_router अभी भी मूल Router पर इंगित करता है।

Router={}Router = setmetatable({},{__index=ElectronicDevice}) (mt_for_router प्रारंभिकरण से पहले) को बदलें।

3

जिस तरह से मुझे ऐसा करना पसंद आया वह क्लोन() फ़ंक्शन को कार्यान्वित करके था।
ध्यान दें कि यह लुआ 5.0 के लिए है। मुझे लगता है कि 5.1 में अधिक निर्मित ऑब्जेक्ट उन्मुख निर्माण हैं।

clone = function(object, ...) 
    local ret = {} 

    -- clone base class 
    if type(object)=="table" then 
      for k,v in pairs(object) do 
        if type(v) == "table" then 
          v = clone(v) 
        end 
        -- don't clone functions, just inherit them 
        if type(v) ~= "function" then 
          -- mix in other objects. 
          ret[k] = v 
        end 
      end 
    end 
    -- set metatable to object 
    setmetatable(ret, { __index = object }) 

    -- mix in tables 
    for _,class in ipairs(arg) do 
      for k,v in pairs(class) do 
        if type(v) == "table" then 
          v = clone(v) 
        end 
        -- mix in v. 
        ret[k] = v 
      end 
    end 

    return ret 
end 

फिर आप एक तालिका के रूप में एक वर्ग को परिभाषित:

Thing = { 
    a = 1, 
    b = 2, 
    foo = function(self, x) 
    print("total = ", self.a + self.b + x) 
    end 
} 

) यह दृष्टांत करने के लिए या इसे से प्राप्त करने के लिए, आप क्लोन (का उपयोग करें और आप उन्हें किसी अन्य तालिका में पास करके चीजों को ओवरराइड कर सकते हैं (या

myThing:foo(100); 
: मिश्रण-इन के रूप में टेबल)

myThing = clone(Thing, { a = 5, b = 10 }) 

फोन के लिए, आपको सिंटैक्स का उपयोग करें

प्रिंट होगा कि:

total = 115 

एक उप-वर्ग प्राप्त करने के लिए, आप मूल रूप से एक और प्रोटोटाइप वस्तु को परिभाषित:

BigThing = clone(Thing, { 
    -- and override stuff. 
    foo = function(self, x) 
     print("hello"); 
    end 
} 

इस विधि बहुत आसान है, संभवतः भी आसान है, लेकिन यह के लिए अच्छी तरह से काम मेरी परियोजना।

1

आपका अपडेट किया गया कोड शब्दशः है, लेकिन काम करना चाहिए। अलावा, आप लिखने में कोई त्रुटि है कि metatables में से एक टूट रहा है है:

 
--Modem inherits from ElectronicDevice 
Modem = setmetatable({},{__index,ElectronicDevice}); 

पढ़ना चाहिए

 
--Modem inherits from ElectronicDevice 
Modem = setmetatable({},{__index=ElectronicDevice}); 

मौजूदा टुकड़ा Modem बनाया metatable एक सरणी जहां पहला तत्व लगभग निश्चित रूप से नहीं के बराबर था (_G.__index का सामान्य मान जब तक आप strict.lua या कुछ समान नहीं कर रहे हैं) और दूसरा तत्व ElectronicDevice है।

Lua Wiki विवरण मेटाटेबल्स को थोड़ी अधिक गड़बड़ाने के बाद समझ में आता है। एक चीज जो सामान्य पैटर्न को सही होने के लिए आसान बनाने के लिए थोड़ा बुनियादी ढांचा बनाने में मदद करती है।

मैं PiL में ओओपी पर अध्याय पढ़ने की भी सिफारिश करता हूं। आप अध्यायों और मेटाटेबल्स पर भी अध्याय दोबारा पढ़ना चाहेंगे। इसके अलावा, मैंने पहले संस्करण की ऑनलाइन प्रति से जुड़ा हुआ है, लेकिन दूसरी की एक प्रति मालिकाना अत्यधिक अनुशंसित है। संबंधित Lua Gems पुस्तक में कुछ लेख भी हैं जो संबंधित हैं। यह भी सिफारिश की है।

4

आप पहिया बदलने की नहीं करना चाहते हैं, वहाँ कई ऑब्जेक्ट मॉडल को लागू करने के लिए एक अच्छा लुआ पुस्तकालय है। इसे LOOP कहा जाता है।

1

उपवर्ग के लिए एक और सरल दृष्टिकोण

local super = require("your base class") 
local newclass = setmetatable({}, {__index = super }) 
local newclass_mt = { __index = newclass } 

function newclass.new(...) -- constructor 
    local self = super.new(...) 
    return setmetatable(self, newclass_mt) 
end 

तुम अब भी सुपर क्लास से कार्यों भले ही ओवरराइट उपयोग कर सकते हैं

function newclass:dostuff(...) 
    super.dostuff(self,...) 
    -- more code here -- 
end 

जब सुपर क्लास कार्य करने के लिए स्वयं को पारित एक डॉट उपयोग करने के लिए मत भूलना

संबंधित मुद्दे