lua入門筆記1 類型 表達(dá)式 語句 函數(shù)

從0開始學(xué)lua,給自己記一個筆記,使用書籍 lua程序設(shè)計(第二版),電子工業(yè)大學(xué)出版社

lua的中文API
)

此篇包含的內(nèi)容有
  • 類型
  • 表達(dá)式
  • 語句
  • 函數(shù)

下面開始正式內(nèi)容,有錯誤歡迎指出,小菜一個

1類型

  • table(表)

  1. 具有哈希結(jié)構(gòu)的關(guān)聯(lián)數(shù)組

  2. 可以通過除了nil外仍和類型的值來索引它,當(dāng)需要創(chuàng)建新條目(entry)時,table會自動增長

  3. lua中主要的、僅有的數(shù)據(jù)結(jié)構(gòu)機(jī)制

  4. lua中用table來表示模塊(module)、包(packge)、對象(object)例如 io.read 實(shí)際是 io模塊中的read函數(shù),通過key read在io表中進(jìn)行索引

  5. lua中table既不是“值”也不是“變量”而是“對象”,可以當(dāng)做一種動態(tài)分配的對象,程序僅持有一個對他們的引用(||指針)lua不會暗中產(chǎn)生table的副本或者創(chuàng)建新的table

  6. table永遠(yuǎn)是匿名的anonymous,一個持有table的變量與table自身沒有固定的關(guān)聯(lián)性
    當(dāng)一個程序再也沒有對一個table的引用時,lua的垃圾收集器(garbage collector)最終會刪除該table并復(fù)用他的內(nèi)存

  7. 當(dāng)table中的某個元素沒有被初始化時,它的內(nèi)容就為nil。通過將nil賦予table某個元素來刪除該元素,類似于全局變量。因?yàn)閘ua將全局變量存儲在一個普通的table中

  8. 數(shù)組通常你以1作為索引的起始值,并且有很多機(jī)制依賴于此慣例

  9. 長度操作符 # 用于返回一個數(shù)組或線性表的最后一個索引值(或?yàn)槠浯笮?) 如

for i=1 #a do 
  print(a[i]) 
end
  1. lua將nil作為界定數(shù)組結(jié)尾的標(biāo)志,當(dāng)一個數(shù)組有空隙(hole)即中間有值為nil時,長度操作符會認(rèn)為這些nil元素就是結(jié)尾。如果需要處理此類數(shù)據(jù),使用table.maxn,他會返回table的最大正索引數(shù)
  • userdata(自定義類型)

可以將任意C語言類型的數(shù)據(jù)存儲到lua變量中 lua中沒有太多的預(yù)定義操作 只能驚醒賦值和相等性測試

  • boolean(布爾)

true和false lua中的任何一個值都可以表示一個條件。不同于有些語言,lua中只有false和nil為假,其他任何值都為真

  • nil(空)

只有一個值,主要用于和其他任何值。一個全局變量在第一次賦值前的默認(rèn)值就是nil

  • thread(線程)

具體細(xì)節(jié)之后再講內(nèi)容較多

  • funtion(函數(shù))

  1. lua中作為第一類值來看待,函數(shù)可以存儲在變量中 并可以當(dāng)做參數(shù)傳遞,(不同于c++,函數(shù)是第二類值,只能用過指向函數(shù)地址的函數(shù)指針來傳遞) 可以通過參數(shù)傳遞給其他函數(shù) 也可以作為其他函數(shù)的返回值

  2. lua所有的標(biāo)準(zhǔn)庫都是用C語言寫的,標(biāo)準(zhǔn)庫中包括對字符串的操作、table的操作、I/O、操作系統(tǒng)的功能調(diào)用、數(shù)學(xué)函數(shù)和調(diào)試函數(shù)

  • string(字符串)

  1. 不能像c一樣直接修改字符串的值,每一次修改需要重新創(chuàng)建一個新的字符串
string a="11"; a+="2";   --錯誤
string a="11" a="112"   --正確
string a="11".."2"          --正確,lua中 .. 為字符串連接符
  1. 享元模式,相同字符串指向同一片內(nèi)存空間

  2. 有自動內(nèi)存管理機(jī)制所托管(gc)

  3. 轉(zhuǎn)義字符表

轉(zhuǎn)義字符: 
\a 響鈴
\b 退格
\f 提供表格
\n 換行
\r 回車
\t 水平制表
\v 垂直制表
\\ 反斜杠
\" 雙引號
\' 單引號
  • number(數(shù)字)

  1. 用于表示實(shí)數(shù),lua中沒有整數(shù)類型 lua中的任何數(shù)字都可以表示任何32位整數(shù) 使用雙精度來表示一個 整數(shù)

  2. 可以使用科學(xué)計數(shù)法,如 0.4 4.37e6

2 表達(dá)式

  • 算術(shù)操作符

二元:
+ 加法
- 減法
* 乘法
/ 除法
^ 指數(shù),右結(jié)合
% 取模
一元:
- 負(fù)號

--關(guān)于%運(yùn)算,規(guī)則如下:
a % b == a - floor(a/b) * b
--對于實(shí)數(shù)來說:
x%1 --> x的小數(shù)部分
x-x%1 --> x的整數(shù)部分
x-x%0.01 --> x精確到小數(shù)點(diǎn)后兩位
  • 關(guān)系操作符

>
<
<=
>=
==
~=(!=)

對于table、userdata 和函數(shù),lua是做引用比較的。只有當(dāng)他們引用同一個對象是,才認(rèn)為相等
只能對于兩個數(shù)字或兩個字符串做大小型比較 對于 "0"與0,是不相同的

  • 邏輯操作符

and ( && )
or ( || )
not ( ! )

  1. 與條件控制語句相同,所有的邏輯操作將false和nil視為假,而其他任何東西都為真。
  2. 對于 and 和 or 來說,都是用 短路求值,也就是說他們只會在需要時哦按段第二個操作數(shù)(如and前為假,lua變不判斷之后)
    常用操作:
x=x or v (若x為空賦默認(rèn)值v)
max=(x>y)and x or y (返回最大值)
  • 字符串連接

  1. ".." (字符串連接符) "hello ".."world" -->"hello world"
  2. 在操作中如果任意一個操作室是數(shù)字,lua會將其轉(zhuǎn)換成一個字符串
  3. lua中字符串是不可變值,連接操作只會創(chuàng)建 一個新的字符串
  4. 右結(jié)合
  • table構(gòu)造式

  1. 用于創(chuàng)建和初始化table
  2. 最簡單的構(gòu)造式為{}空構(gòu)造式,創(chuàng)建一個空的table
    初始化數(shù)組:
words={"a","b","c","d","e"}  printa(a[3])          --> c
a={x=10,y=20} ==> a=[]; a.x=10; a.y=20;
構(gòu)造式{x=0,y=0} ==> {["x"]=0,["y"]=0}
--在一個構(gòu)造式中,除了逗號還可以用分號。一般用分號用于分隔構(gòu)造式中不同的成分,例如  
{x=10,y=45;"one","two","three"}

3.語句

  • 賦值

  1. 普通賦值 與c++相似差異在于多重賦值

  2. lua 中允許多重賦值,例如 a,b = 10 ,2x 賦值后,a為10,b為2x

  3. 在多重賦值中,lua先對等號右邊所有元素求知,然后才執(zhí)行賦值 如 x,y=y,x 交換x與y的值

  4. lua總會將有編制的個數(shù)調(diào)整到與左邊變量的個數(shù)一致。 規(guī)則是 若右邊值數(shù)量少,則多語的變量會被賦值為nil ;若右邊值多,則多于的值會被丟棄
    注意: a,b,c=0 賦值結(jié)果為 0 nil nil

  5. 多重賦值一般用于交換兩個變量或接收函數(shù)的多個返回值(lua中函數(shù)允許返回多個返回值)

  • 局部變量與塊

  1. 通過local語句來創(chuàng)建局部變量

  2. 局部變量的作用域僅限于生命他們的那個塊。一個塊(block)是一個控制結(jié)構(gòu)的執(zhí)行體,或者是一個函數(shù)的執(zhí)行體再或是一個程序塊

x=10
local i =1    -- 程序塊中的局部變量

while i<=x do
   local x=i*2       --while循環(huán)中的局部變量
   print(x)
end

if  i>20 then 
     local x              -- 新局變量x
     x=20               
     print(x+2)         --成功輸出22,局部x
else
     print(x)              --成功輸出10,全局
end

print(x)                    --輸出10 全局

--如果是交互模式,可能不是此結(jié)果。
--交互模式中 每行輸入的內(nèi)容自身就形成了一個程序塊 
--避免此情況需要使用關(guān)鍵字 do-end


do
     local a2=2*a
     local d=(b^2-4*a*c)^{1/2}
     x1=(-b+d)/a2
     x2=(-b-d)/a2
end                   --a2和d的作用域至此結(jié)束
print(x1,x2)
  1. 在編程中盡可能的使用局部變量,這是一種良好的編程風(fēng)格 可避免一些無用的名稱引入全局環(huán)境,而且訪問局部變量比訪問全局變量更快 切在作用域結(jié)束時,便會消失 垃圾回收器便可釋放該值

  2. 在lua中有一種習(xí)慣寫法時

 local foo=foo

這句代碼創(chuàng)建了一個局部變量foo,并用全局變量foo的值初始化它,如果后續(xù)其它函數(shù)改變了全局foo的值,那么可以在這里先將他的值保存起來。這種方法還可以加速在當(dāng)前作用域中對foo的訪問

  1. 在需要時才聲明局部變量,使得其在初始化時就擁有一個有意義的初值,并且縮短變量的作用域 這樣有助于提高代碼的可讀性
  • 控制結(jié)構(gòu)

1. 語法

if then else 
if a<0 then a=0 end
if a<b then return a else return b end
if line>MAXLINES then
    showpage()
    line=0
end
-- =============================
多個嵌套 
if a==1 then 
  a=2
  elseif a==2 then 
  a=3
  else a=4
end
-- =============================
while
local i=1
while a[i] do
   print(a[i])
   i=i+1
end

repeat 一條repeat-until 語句重復(fù)執(zhí)行其循環(huán)知道條件為真是結(jié)束

--打印一行不為空的內(nèi)容
repeat
    local num=io.read()
until num>0                

2. for循環(huán)
2.1 數(shù)字型for

for var=exp1,exp2,exp3 do
    <執(zhí)行體>
end
--表示var從exp1變化到exp2,每次以exp3為步長(默認(rèn)為1)
for i=1,10 do print(i)  end       --正序輸出1-10(包含10)
for i=10,1,-1,do print(i) end    --倒敘輸出1-10(包含1)

不要在循環(huán)過程中修改控制變量(i)的值,跳出直接break

2.2 泛型for(foreach)

泛型for循環(huán)通過一個迭代器(iterator)函數(shù)來遍歷所有值

for i ,v in ipairs(a) do print(v) end   --打印數(shù)組a的所有值

Lua基礎(chǔ)庫 提供了ipairs,這是一個用于遍歷數(shù)組的迭代器函數(shù)。在每次循環(huán)中,i會被賦予一個新的索引值,同事c被賦予一個對應(yīng)于該索引的數(shù)組元素值

標(biāo)準(zhǔn)庫提供的幾種迭代器:

io.lines --迭代文件中的每行
pairs --迭代table元素
ipairs --迭代數(shù)組元素
string.gmatch --迭代字符串中帶刺

同時,也可以自行編寫迭代器

3. break/return
與其他語言基本相同,不同是break與return 只能是一個舉哀的最后一條語句,或者是end else until前的一條語句

4.函數(shù)

  • 基本屬性

lua中函數(shù)可沒有返回值(return 語句)此時返回的是nil

function testPrint()
  print "test print"
end

local t=testPrint()
  print(type(t))           -- nil

正常情況后面必須跟隨圓括號,除以下特例:一個函數(shù)只有一種參數(shù),且改參數(shù)是字面字符串或table構(gòu)造式

print "hello world" ==>print("hello world") 
dofile 'a.lua' <==> dofile('a.lua')

為面向?qū)ο笫降恼{(diào)用提供了一種特殊語法: 冒號操作符 例如:

o.foo(o,x) ==> o:foo(x) --隱含將o作為函數(shù)的第一個參數(shù)

lua中形參數(shù)量與實(shí)參數(shù)量可以不同,會自動調(diào)整數(shù)量(規(guī)則和多重賦值相同)

function f(a,b) return a or b end
f(3)a=3,b=nil
f(3,4) a=3,b=4
f(3,4,5) a=3,b=4 5被舍棄
  • 多重返回值

lua具有一項(xiàng)與其他語言不同的特征,允許函數(shù)返回多個結(jié)果 例如

s,e=string.find("hello lua user","lua") --如果找到返回匹配的起始字符和結(jié)尾字符的索引

編寫具有多返回值的函數(shù):

function testReturn(n)
  if n>0 then
    return 1,2
  else
    return 3
  end
end -- n>0返回1,2 否則返回3

lua會調(diào)整一個函數(shù)的返回值類型數(shù)量以適應(yīng)不同的調(diào)用情況,如下。

  1. 若將函數(shù)調(diào)用作為一條單獨(dú)語句時,lua會丟棄所有的返回值
  2. 若將函數(shù)作為表達(dá)式的一部分調(diào)用時,lua只保留函數(shù)的第一個返回值
  3. 當(dāng)函數(shù)是一系列表達(dá)式中的最后一個元素時,才能獲得 他的所有返回值(多重賦值,函數(shù)調(diào)用時傳入的參數(shù)列表。table的構(gòu)造式、return語句)
function foo() return 1 ,2 end
x,y=foo() --x=1 y=2
x,y=foo(),3 --x=1 y=3
  1. 當(dāng)一個函數(shù)調(diào)用作為另一個函數(shù)調(diào)用的最后一個實(shí)參時,第一個函數(shù)的所有返回值豆?jié){作為實(shí)參傳入第二個參數(shù)
print(foo()) -- 1 2
print(foo(),3) --1 3
  1. 當(dāng)foo2出現(xiàn)在一個表達(dá)式中時,lua會將其返回值數(shù)量調(diào)整為1 如
print(foo().."x") --1x
  1. table表達(dá)式可以完整的接收一個函數(shù)調(diào)用的所有結(jié)果(只有當(dāng)一個函數(shù)調(diào)用作為最后一個元素時發(fā)生)
t={foo()} --t[1]=1 t[2]=2
t={foo(),3} --t[1]=1,t[2]=3
t={0,foo()} --t[1]=0 t[2]=1 t[3]=2 
  1. 也可以將一個函數(shù)調(diào)用放入一對圓括號中,從而只返回一個結(jié)果如
print((foo())) --輸出1
  1. 關(guān)于多重返回還有一個特殊函數(shù) upack 他接受一個數(shù)組作為參數(shù),并從1開始返回所有元素
print(unpack ({10,20,30}) ) --10 20 30
a,b=unpack(10,20,30) --a=10,b=20 30被丟棄
  1. unpack的一項(xiàng)重要用途體現(xiàn)在泛型調(diào)用(generic call) 機(jī)制中 ASNI C 中(c的標(biāo)準(zhǔn))是無法編寫泛型調(diào)用的代碼 最多是聲明一個可以接受長參數(shù)的函數(shù) 或者通過一個函數(shù)指針來調(diào)用不同的函數(shù) 并且無法在同一次函數(shù)調(diào)用中傳入動態(tài)數(shù)量的參數(shù),每次在調(diào)用時必須傳入固定數(shù)量的參數(shù) 并且每個都要具有確定的類型 而lua中可以做到
    unpack函數(shù)等價于 return list[1],list[2].....list[j] (j=#list)
  • 變長參數(shù)

lua中的函數(shù)還可以接受不同數(shù)量的實(shí)參,例如

function Add(...)
  local s=0
  for i,v in ipairs{...} do
    s=s+v
  end
  return s
end  

print(add(3,4,10,25,12))       --> 54
  1. 參數(shù)中的3個點(diǎn) (...) 表示該函數(shù)可接受不同數(shù)量的實(shí)參,一個函數(shù)要訪問它的變長參數(shù)時,仍需用到三個點(diǎn)(...)此時這三個點(diǎn)是作為一個表達(dá)式來使用的 表達(dá)式{...}表示一個由所有變長參數(shù)構(gòu)成的數(shù)組

  2. 表達(dá)式 "..." 的行為類似于一個具有多重返回值的函數(shù),他返回的是當(dāng)前函數(shù)的所有變長參數(shù)

  3. 具有變長參數(shù)的函數(shù)同樣也可以擁有任意數(shù)量的固定參數(shù),但固定參數(shù)必須放在變長參數(shù)之前。

  4. 在遍歷一個變長參數(shù)時通常只需用到{...]如同訪問一個table一樣。然而如果變長參數(shù)中有我們刻意傳入的nil值,則需 用到函數(shù)select,規(guī)則如下

如果 index 是個數(shù)字, 那么返回參數(shù)中第 index 個之后的部分; 負(fù)的數(shù)字會從后向前索引(-1 指最后一個參數(shù))。 否則,index 必須是字符串 "#", 此時 select 返回參數(shù)的個數(shù)。如

for i=1,select('#',...) do 
  print(select('i',...)) 
end
  • 具名實(shí)參

類似于c/c++中具有默認(rèn)值的參數(shù) int GetAge(int age=0) 但lua中不支持這種語法,我們可以通過一些操作達(dá)到相同的效果,如下示例

function Window(options)
--檢查必要參數(shù)
    if type(options.title)~="string" then error("no title") end
    if type(options.width)~=“number" then  error("no width") end
    if type(options.height)~= "number" then error("no height")  end
--其他參數(shù)都是可選的
  _Window(options.title,                        -- _Window 真正的創(chuàng)建窗口函數(shù)
                    options.x or 0                      --默認(rèn)值
                    options.y or 0                      --默認(rèn)值
                    options.width,options.height
                    options.background or "white"  --默認(rèn)值
                   )
end
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我真的又想逃避了,每天早上六點(diǎn)二十起床,坐地鐵,早上七點(diǎn)四十五到公司,然后就是重復(fù)的工作,接打電話,我以為客服是一...
    小九郎閱讀 139評論 0 0
  • 1、如果你愛上了某個星球的一朵花。那么,只要在夜晚仰望星空,就會覺得漫天的繁星就像一朵朵盛開的花。(這就好比你喜歡...
    千巖萬宇_閱讀 576評論 0 0

友情鏈接更多精彩內(nèi)容