1、lua學習之入門(一)----環境搭建
2、lua學習之入門(二)----基礎語法1
3、lua學習之入門(二)----基礎語法2
4、lua學習之入門(三)----函數
???? 在LUA里函數是個十分重要的內容,因為我們實際開發的時候,用的最多的就是函數,用函數是封裝各個實現,在Q群里曾經聽一些大蝦說過,寫LUA必須要懂得閉包,常用系統函數,還有范型for寫迭代器,最后就是編譯和運行還有錯誤信息.其實這章,我就卡了一下殼,卡殼的地方在閉包,因為我沒有完全理解閉包的作用,和閉包的好處,網上也沒有明確的說明閉包的優劣,所以閉包的概念,我也只能以個人感覺去寫,如果我說得不對,歡迎賜教.如果對閉包理解很深,歡迎來指教...你要偶拜你為師也行,達者為師啊,偶很好學的.
函數有兩種用途:1.完成指定的任務,這種情況下函數作為調用語句使用;2.計算并返回值,這種情況下函數作為賦值語句的表達式使用。
?? 其實我們接觸最早的,就是函數,還記得我們的第一個LUA嗎?print();這就是一個函數.可以理解****()都可以當做是函數,其實大部分編程語言的函數都是以這個方式一共調用的.認識了什么是函數,那么我們就自己編寫一個函數吧
function?maxFun(a
,
b)
???
if
?a
>
b?then
???
return
?a;
???
else
?????
return
?b;
??end
end

--
我們用一個輸出語句把我們的函數結果顯示出來
,
證明我們寫的函數沒有問題

print
(maxFun(
4
,
3
));
上面這個函數
,
其實很簡單就是比較兩個數的大小
.
最后運行的結果我們得到結果是4
,
這里使用的是函數的第1種任務
,
判斷兩個數的大小
,
在LUA里函數是可以返回多個值的
,
這個點和其他編程語言有很大的區別
,
那就很容易造成錯覺
,
多個返回值
,
那我如何獲得各個返回值呢
?
看例子

function?returnAnyValue()
????????
return
?
1
,
2
,
3
,
4
;
???end

????a
,
b
,
c
,
d?
=
?returnAnyValue();
e
,
f
,
g?
=
?returnAnyValue();
h
,
i
,
j
,
k
,
l?
=
?returnAnyValue();

--
[[
print
(
"
a:
"
..
a
..
"
?b:
"
..
b
..
"
?c:
"
..
c
..
"
?d:
"
..
d
..
"
?e:
"
..
e
..
"
?f:
"
..
f
..
"
?g:
"
..
g
..
"
?h:
"
..
h
..
"
?i:
"
..
i
..
"
?j:
"
..
j
..
"
?k:
"
..
k
..
"
?l:
"
..
l
..
"
?!
"
);
]]
--
這樣編譯是出錯的
,
提示告訴我們l為nil不能輸出
.
--
所以我們把程序修改為

print
(
"
a:
"
..
a
..
"
?b:
"
..
b
..
"
?c:
"
..
c
..
"
?d:
"
..
d
..
"
?e:
"
..
e
..
"
?f:
"
..
f
..
"
?g:
"
..
g
..
"
?h:
"
..
h
..
"
?i:
"
..
i
..
"
?j:
"
..
j
..
"
?k:
"
..
k
..
"
?!
"
);

結果如下
:
???a
:
1
?b
:
2
?c
:
3
?d
:
4
?e
:
1
?f
:
2
?g
:
3
?h
:
1
?i
:
2
?j
:
3
?k
:
4
雖然我們不能輸出L的值,但是我們根據錯誤提示可以知道l的值是nil的.
論述完返回值,那么我們要看參數數了,LUA支持可變參數的模式的使用的方法和C語言的差不多,不熟悉的可以先學C語言,畢竟我看到的LUA大多數都是嵌入C中的,所以C/C++至少你要會.
好了我們要進入我覺得比較難的點:閉包
在我接觸的編程語言里,其實還沒發現過閉包的概念,坦白的說一句,就是LUA我才接觸閉包的.閉包從網上的資料來看,就是JAVASCRIPT里的匿名函數的使用(我接觸新語言的時候,總喜歡用自己接觸過的語言去進行對比,去學習.我覺得這種學習的方法還是比較有效果的,有興趣的朋友也可以試試這個方法.),在我看了網上公開的閉包程序,最大的特點就是使用,外面的函數有自己的局部變量,內部的匿名函數使用了外部函數的局部變量.有點像面向對象思想里的意思,后來我在LUA的一個論壇看到一篇關于閉包的定義,如下:
當一個函數內部嵌套另一個函數定義時,內部的函數體可以訪問外部的函數的局部變量,這種特征我們稱作詞法定界。雖然這看起來很清楚,事實并非如此,詞法定界加上第一類函數在編程語言里是一個功能強大的概念,很少語言提供這種支持。
技術上來講,閉包指值而不是指函數,函數僅僅是閉包的一個原型聲明
這個是我在網上找的一個關于閉包的例子,個人感覺水平有限.可能使用網上的例子更有說服力
這個例子主要說明的是在外部函數和內部函數之見參數的使用,函數中就可以直接用變量進行傳值,這里需要說明一下的是table.sort(存放元素的數組,排序函數)具體的等后面我介紹常用庫的時候說.只要知道是表排序就好.
函數就寫出來的,但是我們需要更直觀的看到這些資料
所以我在最下面加上了如下代碼
print
(
"
---------
"
)
sortbygrade?(names
,
?grades);

for
?v?in?pairs(names)?
do
print
(names[v])
end
輸出結果為
Mary
Peter
Paul我將grades = {Mary = 7, Paul = 8, Peter = 9}改了再看效果
Peter
Paul
Mary
function?newCounter()

????local?i?=?0

????return?function()?????--?anonymous?function

???????i?=?i?+?1

????????return?i

????end

end

?

c1?=?newCounter()

print(c1())??-->?1

print(c1())??-->?2

print(c1())??-->?3

結果代碼里已經顯示了,我就不說了,但是大家看到這個結果?你想到了什么?
對象?就是對象,看以下C#代碼
public?class?CC


{
????private?int?a;

????public?CC()

????
{
???????a=0;
????}

????public?int?newCounter()

????
{
???????this.a=this.a+1;
???????retrun?this.a;
????}
}如果LUA代碼里C1=newCounter();C2=newCounter()
?print(c2())--->1
是不是跟我們聲明一個對象十分的類似呢?所以我推斷閉包在一定程度上實現了部分面向對象的功能,肯定有一定的差別的,我只是說類似..而且我看代碼有點像C語言去實現面向對象的感覺...
閉包還可以實現類似JAVA里沙箱的功能,(來自網上,我并沒有運行這段代碼)
do

????local?oldOpen?=?io.open

????io.open?=?function?(filename,?mode)

???????if?access_OK(filename,?mode)?then

???????????return?oldOpen(filename,?mode)

???????else

???????????return?nil,?"access?denied"

???????end

????end

end

*正確的尾調用
這個迷宮游戲是典型的狀態機,每個當前的房間是一個狀態。我們可以對每個房間寫一個函數實現這個迷宮游戲,我們使用尾調用從一個房間移動到另外一個房間。一個四個房間的迷宮代碼如下:

function?room1?()

????local?move?=?io.read()

????if?move?==?"south"?then

???????return?room3()

????elseif?move?==?"east"?then

???????return?room2()

????else

???????print("invalid?move")

???????return?room1()???--?stay?in?the?same?room

????end

end

?

function?room2?()

????local?move?=?io.read()

????if?move?==?"south"?then

???????return?room4()

????elseif?move?==?"west"?then

???????return?room1()

????else

???????print("invalid?move")

???????return?room2()

????end

end

?

function?room3?()

????local?move?=?io.read()

????if?move?==?"north"?then

???????return?room1()

????elseif?move?==?"east"?then

???????return?room4()

????else

???????print("invalid?move")

???????return?room3()

????end

end

?

function?room4?()

????print("congratilations!")

end

我們可以調用room1()開始這個游戲。

如果沒有正確的尾調用,每次移動都要創建一個棧,多次移動后可能導致棧溢出。但正確的尾調用可以無限制的尾調用,因為每次尾調用只是一個goto到另外一個函數并不是傳統的函數調用

(以上代碼來源網上)
正確尾調用論述的意義在于..棧溢出的問題,不正確的尾調用是存在棧溢出問題的.
這篇寫的我自己都不是很滿意...因為這個東西..需要點時間消化...等我消化了再來整理一下,就好象開頭,我也是一個LUA新手,我只能把我認識的弄出來,而且正確上..也非絕對..其實我的目的只是傳播我的學習的思想.
明鏡臺
posted on 2009-05-14 13:14
^喬喬^ 閱讀(2084)
評論(0) 編輯 收藏 引用 所屬分類:
Lua學習筆記