lua面向對象編程之點號與冒號的差異詳細比較

作爲一名lua新手,在使用騰訊xLua框架時,也是一邊在學習着Lua,對於點和冒號的用法一直理解的不夠透徹,找到了這篇文章,原文地址:

http://www.cnblogs.com/youxilua/archive/2011/07/28/2119059.html

首先,先來一段在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進行面向對象的編程,聲明方法和調用方法統一用冒號,對於屬性的調用全部用點號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章