简体   繁体   中英

Lua class instance with nested tables

Simple Lua game with simple class like so:

creature = class({ 
name = "MONSTER BADDY!",

stats = { power = 10, agility = 10, endurance = 10, filters = {} },

other_things = ...
})

creatureA = creature.new()

creatureB = creature.new()

creatureA.name = "Frank"

creatureB.name = "Zappa"

creatureA.stats.agility = 20

creatureB.stats.power = 12

-- blah blah blah

Non table values are individual to each instance, but table values are shared among all instances and if I modify a stats.X value in one instance, all other instances see the same stats table.

Q1: Is my OO implementation flawed? I tried LOOP and the same result occured, is there a fundamental flaw in my logic?

Q2: How would you have each instance of creature have it's own stats table (and sub tables)?

PS. I cannot flatten my class table as it's a bit more complicated than the example and other parts of the code are simplified with this nested table implementation.

It works like that because class instances have the class table set as __index in their metatable ( well, most implementations work that way ) So if you access creatureA.stats ( and it can't find stats on creatureA , thus falls to __index ) it returns creature.stats . Maybe you should read up on Lua 5.1 Reference Manual: Metatables

You won't be able to declare per-instance variables in the class's table constructor ( unless you deep copy everything from the class table to the instance, which would be quite expensive )

You'll have to do it in whatever initializer function your class implementation uses:

creature = class
{
     __init = function(self, ...)
         self.stats = {power = 10, agility = 10, endurance = 10, filters = {}}
     end,
}

class is not a standard function in Lua. You don't say if you've borrowed it from Roberto, rolled your own, or what. But my guess is that you want to change the new method so that it does a deep copy of the prototype instead of a shallow copy:

function deep_copy(v)
  if type(v) == 'table' then
    local u = { }
    for k, v in pairs(v) do
      u[k] = v
    end
    setmetatable(u, getmetatable(v))
    return u
  else
    return v
  end
end

(Alert: I haven't tried to compile this code, let alone run it.)

When creating a new creature you could always create a new stats table for it if you don't want it to be shared.

creature = class({ 
    name = "MONSTER BADDY!",
    stats = stats.new({ power = 10, agility = 10, endurance = 10, filters = {} }),
    other_things = ...
})

Power, agility etc. would be passed as arguments in the constructor for stats .

That function of yours called class looks suspicious. I go would for simplest possible code. Here is a monster class file. Nothing fancy and some people would say it lacks some fluff but at least I can read the code myself next week too.

-- Class object

monster = {}
monster.__index = monster

-- Class methods

function monster.new(name)
    local o = {}
    o.name = name
    o.stats = {power = 10, agility = 10, endurance = 10, filters = {}}
    setmetatable(o, monster)
    return o
end

function monster:shout()
    print('Aaaaaaa! My name is ' .. self.name .. '!')
end

And here is the output:

> lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require 'monster'
> m = monster.new('Katla')
> m:shout()
Aaaaaaa! My name is Katla!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM