Lua学习笔记:面向对象

https://blog.csdn.net/liutianshx2012/article/details/41921077

Lua 中只存在表(Table)这么唯一一种数据结构,但依旧可以玩出面向对象的概念。

添加成员函数

好吧,如果熟悉 C++ 还是很好理解类似的进化过程的:如果说 struct 里可以添加函数是从C 过渡到 C++ 的第一认识的话,为 Table 添加函数也可以算是认识 Lua 是如何面向对象的第一步吧。

  1.  
    player = { health = 200 } --> 一个普通的 player 表,这里看作是一个对象
  2.  
    function takeDamage(self, amount)
  3.  
    self.health = self.health - amount
  4.  
    end
  5.  
     
  6.  
    takeDamage(player, 20) --> 调用

如何将独立的 takeDamage 塞进 player 中咧?答案是直接定义进去:

  1.  
    player = { health = 200 }
  2.  
    function player.takeDamage(self, amount)
  3.  
    self.health = self.health - amount
  4.  
    end
  5.  
     
  6.  
    player.takeDamage(player, 20) --> 调用

这样就相当于在 player 表中添加了一个叫做 takeDamage 的字段,和下面的代码是一样的:

  1.  
    player = {
  2.  
    health = 200,
  3.  
    takeDamage = function(self, amount) --> Lua 中的函数是 first-class value
  4.  
    self.health = self.health - amount
  5.  
    end
  6.  
    }
  7.  
     
  8.  
    player.takeDamage(player, 20) --> 调用

调用时的 player.takeDamage(player,20) 稍显不和谐(据说用术语叫做 DRY),于是就要出动「冒号操作符」这个专门为此而生的语法糖了:

  1.  
    player:takeDamage(20) --> 等同于 player.takeDamage(player, 20)
  2.  
    function player:takeDamage(amount) --> 等同于 function player.takeDamage(self, amount)

从对象升华到类

类的意义在于提取一类对象的共同点从而实现量产(我瞎扯的 >_<)。同样木有 Class 概念的 Javascript使用 prototype 实现面向对象,Lua则通过 Metatable 实现与 prototype 类似的功能。

  1.  
    Player = {}
  2.  
     
  3.  
    function Player:create(o) --> 参数 o 可以暂时不管
  4.  
    o = o or { health = 200 } --> Lua 的 or 与一般的 || 不同,如果非 nil 则返回该非 nil 值
  5.  
    setmetatable(o, self)
  6.  
    self.__index = self
  7.  
    return o
  8.  
    end
  9.  
     
  10.  
    function Player:takeDamage(amount)
  11.  
    self.health = self.health - amount
  12.  
    end
  13.  
     
  14.  
    playerA = Player:create() --> 参数 o 为 nil
  15.  
    playerB = Player:create()
  16.  
     
  17.  
    playerA:takeDamage(20)
  18.  
    playerB:takeDamage(40)
  19.  
     

顾名思义 Metatable 也是一个 Table,可以通过在其中存放一些函数(称作metamethod)从而修改一些默认的求值行为(如何显示为字符串、如何相加、如何连接、如何进行索引)。Metatable的 __index 域设置了「如何进行索引」的方法。例如调用foo.bar 时,如果在 foo 中没有找到名为 bar 的域时,则会调用Metatable:__index(foo,bar)。于是:

playerA:takeDamage(20)

因为在 playerA 中并不存在 takeDamge 函数,于是求助于Metatable:

getmetatable(playerA).__index.takeDamage(playerA, 20)

带入 Metatable 后:

Player.__index.takeDamage(playerA, 20)

因为 Player 的 __index 在 create 时被指定为 self,所以最终变为:

Player.takeDamage(playerA, 20)

于是 takeDamage 的 self 得到了正确的对象 playerA

继承

继承是面向对象的一大特性,明白了如何创建「类」,那么继承也就比较明了了,还记得大明湖畔的参数 o 么?

  1.  
    RMBPlayer = Player:create()
  2.  
    function RMBPlayer:broadcast(message) --> 为子类添加新的方法
  3.  
    print(message)
  4.  
    end
  5.  
    function RMBPlayer:takeDamage(amount) --> 子类重载父类方法
  6.  
    self.health = self.health - amount / (self.money / 100)
  7.  
    end
  8.  
     
  9.  
    vip = RMBPlayer:create { money = 200 } --> 子类添加新成员(单个 Table 作为参数可以省略括号)
  10.  
     
  11.  
    vip:takeDamage(20)
  12.  
    vip:broadcast("F*ck")

以上便是 Lua 中实现面向对象的基本方法。

========================================

最新文章

  1. EF之ExecuteSqlCommand更新出现无效的解决方案
  2. Mysql表分区几种方式
  3. (第五章)java面向对象之this的作用总结
  4. IE6多出一只猪的经典bug
  5. 怎么做fastreport使用离线数据源
  6. RestTemplate的设置及使用
  7. [物理学与PDEs]第1章第7节 媒质中的 Maxwell 方程组 7.1 媒质中的 Maxwell 方程组
  8. 面试遇到两个稍显变态的题目,mark一下
  9. LeetCode 12 - 整数转罗马数字 - [简单模拟]
  10. DataGridView 访问任意行不崩溃
  11. springboot+thymeleaf+springbootJPA实现一个简单的增删改查
  12. Leeetcode--581. Shortest Unsorted Continuous Subarray
  13. PHP7通过yum源安装及性能测试
  14. noip第10课资料
  15. django 参考
  16. TCP 回顾
  17. windows7 sqlserver2012 无法写入受保护的内存 解决办法
  18. (欧拉公式 很水) Coprimes -- sgu -- 1002
  19. Linux内核同步 - memory barrier
  20. IE8 JSON is not defined

热门文章

  1. MAC系统如何显示隐藏文件解决方法
  2. java对接微信支付
  3. webpack 4.14配置详解
  4. 中国农产品信息网站scrapy-redis分布式爬取数据
  5. PAT (Basic Level) Practice (中文)1002
  6. vue---day01
  7. CSS3实现加载数据动画1
  8. android中activity,window,view之间的关系
  9. Jenkins - 持续集成部署
  10. 远程连接云主机MySql数据库