Lua Object-Oriented Programming - I don't unde

2019-07-11 18:54发布

I'm building a simple game and I've been following the PIL book. Here is the scenario I am basing my game off of: http://www.lua.org/pil/16.1.html

I'm struggling because there is only one module in the book and I'm trying to get 8 modules working together.

Here's a small part of my game: I have a Game module, a Board module and a Input/Output module for now.

I thought I understood when to use colon and when to use period, but I'm not understanding why, in the PIL example, the author is passing in "o" to the "new" method and why there is a colon on that method?

My Game module is supposed to be my highest level module. In it, I would think I would new up the board and input/output modules and get those working together. But what do those "new" (meaning initialize) methods look like for the board and input/output modules?

Here some code I've been working with (simplified):

Game = {}

function Game:new(o)
  o = {} or o
  setmetatable(o, self)
  self.__index = self
  -- need board and input_output instances below
  o.board = Board:new(o)
  o.input_output = Input_Output:new(o)
  return o
end

return Game
----------------------------------------------------
Board = {}

function Board:new(o)
  o = o or {}
  -- need layout attribute here
  o.layout = { create_layout() }
  setmetatable(o, self)
  self.__index = self
  return o
end

return Board
---------------------------------------------------
Input_Output = {}

function Input_Output:new(o)
  o = o or {}
  -- need read and write attributes here
  o.read = stdin
  o.write = stdout
  setmetatable(o, self)
  self.__index = self
  return o
end

return Input_Output

In an OOP language like Ruby, Game would hold instances of my Board and Input_Output classes. Then if I drilled down to game.board, I could see the public attributes and public methods on board.

However, when I am newing up these 2 "classes" in game, something weird is going on. My self and o variables are not what I would expect them to be (I'm using lua_inspect). I seem to maybe be overwriting data in the o variable with each new instance of a module?

I'm so lost and I think it's because of the "new" method. I'm just not getting it.

Can anyone explain? My questions mainly are - what's with the "o" in the example and why is there a colon on the "new" method?

标签: oop lua
3条回答
别忘想泡老子
2楼-- · 2019-07-11 19:27

So to focus on "what's with the 'o' in the example and why is there a colon on the "new" method?":

So Game is the class: it is a table with functions. That's the basic notion of class in Lua. So what is an instance of Game? It is a table whose metatable is its class's table namely Game.

But in Lua a function in a table can't know what table it is in except if it is given this info as call parameter. Lua makes this easy by automatically giving reference to containing table as first parameter to function when you call it with the colon instead of dot. This first param has name "self". So in the "new" function, calling it with colon provides the table that new is defined in as self param, ie the class Game.

So you can see that 'o' is the instance you are creatiing, and you call new with colon because otherwise you would have to give it the class table which would then appear twice in your statement ie colon provides nicer syntax.

查看更多
萌系小妹纸
3楼-- · 2019-07-11 19:29

I trying to explain this. It will also help me to understand this deeper.

So, just look at the example in http://www.lua.org/pil/16.1.html.

Account = {}
function Account:new (o)
  o = o or {}   -- create object if user does not provide one
  setmetatable(o, self)
  self.__index = self
  return o
end

Understand Function in Lua

function foo (x) return 2*x end

is just an instance of what we call syntactic sugar; in other words, it is just a pretty way to write

foo = function (x) return 2*x end

And you know that : is only a syntactic facility for ..

function Account:new (o)

is the same as

function Account.new ( Account, o )

So above all, we know

function Account:new (o)

is the same as

Account.new = function( Account, o )

How do we find something in a Lua Table

a = Account.new

The finding process below:

Find if there is a 'new' key in `Account`? --Yes-- Return `Account.new`
               |
               No
               |
Check if `Account` has a metatable? --No-- Return `nil`
                |
                Yes
                |
Check if there is a 'new' key in the `__index` field of `Account`'s metatable --No-- Return `nil`
                |
                Yes
                |
    Assume `metaAccount` is the metatable of Account
    Return `metaAccount.__index.new`

What does Account:new do

o = o or {} -- just create a new table if the input o is nil

setmetatable(o, self) -- self is Account because of `:`, and set o's metatable to Account

self.__index = self -- the same as Account.__index = Account, this is set the `__index` field of Account, which is o's metatable

return o --return o, a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`

How it works

We define another function

function Account:print() --the same as Account.print = function( self )
    print("Class Account.")
end

a = Account:new() --a is a table which has a metatable `Account`, and `Account` has a `__index` field is also `Account`
a:print() --find a.print in a's metatable `Account` as a function, and run it
-->Class Account.

You shall clear now...

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-07-11 19:30

Actually there's no "official" classes in Lua, so you can implement them any way you want. In this particular implementation o is the new instance, possibly with some pre-defined parameters. It inherits all members of parent, be they values or methods - functions - that's all the same in Lua. If you do not supply an o in this call at all, an empty table will be created for you.

: in function definition is just a syntactic sugar for function Game.new(self, o) - that is, it adds a very first parameter called self.

You should call this function like local my_game = Game:new(). After that, my_game will be a table that have my_game.board and my_game.input_output members.

Your current question is not exactly clear on what do you see and how it is different from what you expect. If you provide more details, I can add more details to answer too.

查看更多
登录 后发表回答