• lua面向对象编程之点号与冒号的差异详细比较


    首先,先来一段在lua创建一个类与对象的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class.new(10,20)
     
    object:test()

    猜一下会输出什么结果呢?

    输出:

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    20    nil
    >Exit code: 0

    我们的y值怎么没了?

    这个原因很简单,因为我们创建一个对象的时候使用了一个 . 号

    在lua程序设计第二版中,有提到当一项操作所作用的”接受者”,需要一个额外的参数来表示该接受者,这个参数通常称为self或this

    然后我们在这段代码加上 self

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class.new(self,10,20)
     
    object:test()

    然后我们在看一下输出

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    10    20
    >Exit code: 0

    这下就正常了!!嗯,每次创建一个对象的时候都有写一个self,会不会感觉很麻烦呢?lua提供了用冒号的方式在一个方法定义中添加一个额外的参数,以及在一个方法调用中添加一个额外的实参

    然后代码改成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object:test()

    输出正常:

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    10    20
    >Exit code: 0

    如果,就这么完的话,本来是一件很欢乐的事情,但是,我尝试了一下以下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class.new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class.new(10,20)
     
    object:test()

    出乎意料的是:

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    10    20
    >Exit code: 0

    代码正常运行….这个让人很费解,本来,点号对方法的操作是需要一个额外的接受者,第一段代码已经说明了这个问题,但是,现在程序有正常运行,令我真是有点费解…

    然后,我接着尝试又发现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class.new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object:test()

    输出结果:

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    table: 003CACA0    10
    >Exit code: 0

    这个只不过跟第一段代码点号和冒号的位置调换了一下,就出现了这样的结果…

    如果,你仔细想想,这里和第一段代码的区别,可以发现,其实,这里就可以证明了冒号其实就是默认传了一个实参到方法中

    为了证明冒号的作用,我改动了一下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class.test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object:test()

    输出的结果是:

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    lua: object.lua:15: attempt to index global 'self' (a nil value)
    stack traceback:
        object.lua:15: in function 'test'
        object.lua:21: in main chunk
        [C]: ?
    >Exit code: 1

    从这里的错误可以看出,没有self这个参数,竟然,方法用的是点号,那我们试一下把对象传进去看下能不能正常运行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class.test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object:test(object)

    遗憾的是这样的改动是错误的,错误的结果也是一样的

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    lua: object.lua:15: attempt to index global 'self' (a nil value)
    stack traceback:
        object.lua:15: in function 'test'
        object.lua:21: in main chunk
        [C]: ?
    >Exit code: 1

    那我们这次尝试下想刚才那样,把方法的点号搞成一致看下效果怎样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class.test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object.test()

    遗憾的是跟之前不一样,还是不能运行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class.test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object.test()
    1
      
    1
    回想一下,冒号的作用可以传递一个实参,对于方法的操作我们需要一个接受者,那么进行以下的改动
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Class = {}
    Class.__index = Class
     
    function Class:new(x,y)
        local temp = {}
        setmetatable(temp, Class)
        temp.x = x
        temp.y = y
        return temp
    end
     
    function Class:test()
        print(self.x,self.y)
    end
     
     
    object = Class:new(10,20)
     
    object.test(object)

    这次输出就正常了

    >lua -e "io.stdout:setvbuf 'no'" "object.lua" 
    10    20
    >Exit code: 0

    这段代码告诉了我们,想要操作一个方法就一定需要一个额外参数来表示该值,对于点号,我们必须显示传递一个实参,才能使程序正常运行,而为了方便,我们可以直接使用冒号来简化操作.

    lua冒号点号

    在lua开发中我们经常会混淆这两者之间的区别,下面通过一个示例来解释:

    Class = {}
    Class.__index = Class
      
    function Class.new(x,y)
        local cls = {}
        setmetatable(cls, Class)
        cls.x = x
        cls.y = y
        return cls
    end
    function Class:test()
    -- 等价于
    -- function Class.test(self)
        print(self.x,self.y)
    end
      
      
    object = Class.new(10,20)
     
    object:test()
    -- 等价于
    object.test(object)

    可以看到: 
    1、 定义的时候: Class:test()与 Class.test(self)是等价的 ,点号(.)要达到冒号(:)的效果要加一个self参数到第一个参数; 
    2、 调用的时候: object:test() 与object.test(object)等价 ,点号(.)要添加对象自身到第一个参数。

    总结:可以把点号(.)作为静态方法来看待,冒号(:)作为成员方法来看待。 

    结论:

    罗嗦了半天其实,可以用一下一句话来避免这个问题:

    用lua进行面向对象的编程,声明方法和调用方法统一用冒号,对于属性的调用全部用点号

  • 相关阅读:
    123
    p1216
    离线可持久化动态树
    线段树合并
    p2024
    树的dfs序,p1539,p1651,,2018/11/08模拟赛T3
    p1460
    CDQ分治,二维数点与三维数点,p1357与p2026与p2027与p2028与p2029
    自动AC机
    平衡二叉树之splay p1998
  • 原文地址:https://www.cnblogs.com/zhepama/p/4280688.html
Copyright © 2020-2023  润新知