zoukankan      html  css  js  c++  java
  • Lua学习笔记:面向对象

    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 中实现面向对象的基本方法。

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

  • 相关阅读:
    利用session防止表单重复提交
    SpEL表达式
    logback logback.xml常用配置详解(三) <filter>
    logback logback.xml常用配置详解(二)<appender>
    logback logback.xml常用配置详解(一)<configuration> and <logger>
    logback的使用和logback.xml详解
    h5 中的 section 标签
    类锁与实例锁
    FreeMarker详解
    Java面试经
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/9315344.html
Copyright © 2011-2022 走看看