ua 是一種輕量小巧的腳本語言,用標準C語言編寫并以源代碼形式開放, 其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。
Lua 是巴西里約熱內盧天主教大學(Pontifical Catholic University of Rio de Janeiro)里的一個研究小組,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所組成并于1993年開發。 —摘抄 http://www.runoob.com/lua/lua-tutorial.html
環境搭建
注意: 在上一篇文章中,OpenResty已經有了Lua的環境,這里安裝的是單獨的Lua環境,用于學習和開發Lua。大多數的電腦是Windowds版本的電腦,Windows版本下載地址http://luaforge.net/projects/luaforwindows/。
Linux和Mac電腦下載地址:http://luajit.org/download.html,安裝命令如下:
wget http://luajit.org/download/LuaJIT-2.1.0-beta1.tar.gz tar -xvf LuaJIT-2.1.0-beta1.tar.gz cd LuaJIT-2.1.0-beta1 make sudo make install
使用IDEA開發的同學,可以通過安裝插件的形式來集成Lua的環境,插件名為EmmyLua,安裝插件后,在Idea的右側欄就會出現Lua的圖標,點擊圖標,就會出現運行Lua代碼的窗口。建議使用該插件,可以免去安裝Lua環境的麻煩。
第一個Lua程序
安裝好環境后,我采用EmmyLua插件的形式,對Lua的入門語法進行一個簡單的講解。 打開EmmyLua的終端,在終端上輸入:
print("hi you")
按ctrl+enter,終端顯示:
hi you
Lua基本數據類型
lua的基本數據類型有nil、string、boolean、number、function類型。
nil 類型
nil類似于Java中的null ,表示空值。變量第一次賦值為nil。
local num
print(num)
num=100
print(num)
終端輸出:
nil
100
number (數字)
Number 類型用于表示實數,和 Java里面的 double 類型很類似。可以使用數學函數 math.floor(向下取整) 和 math.ceil(向上取整) 進行取整操作。
local order=3.99 local score=98.01 print(math.floor(order)) print(math.ceil(score))
輸出:
3
99
string 字符串
Lua 中有三種方式表示字符串: 1、使用一對匹配的單引號。例:’hello’。 2、使用一對匹配的雙引號。例:”abclua 3.字符串還可以用一種長括號(即[[ ]]) 括起來的方式定義
ocal str1='hello world'
local str2="hello lua"
local str3=[["add\name",'hello']]
local str4=[=[string have a [[]].]=]
print(str1) -->output:hello world
print(str2) -->output:hello lua
print(str3) -->output:"add\name",'hello'
print(str4) --
table (表)
Table 類型實現了一種抽象的“關聯數組”。“關聯數組”是一種具有特殊索引方式的數組,索引通常是字符串(string) 或者 number 類型,但也可以是除 nil 以外的任意類型的值。
local corp={ web="www.google.com", --索引為字符串,key="web", -- value="www.google.com" telephone="12345678", --索引為字符串 staff={"Jack", "Scott", "Gary"}, --索引為字符串,值也是一個表 100876, --相當于 [1]=100876,此時索引為數字 -- key=1, value=100876 100191, --相當于 [2]=100191,此時索引為數字 [10]=360, --直接把數字索引給出 ["city"]="Beijing" --索引為字符串 } print(corp.web) -->output:www.google.com print(corp["telephone"]) -->output:12345678 print(corp[2]) -->output:100191 print(corp["city"]) -->output:"Beijing" print(corp.staff[1]) -->output:Jack print(corp[10]) -->output:36
function(函數)
在 Lua 中,函數 也是一種數據類型,函數可以存儲在變量中,可以通過參數傳遞給其他函 數,還可以作為其他函數的返回值。
local function foo() print("in the function") --dosomething() local x=10 local y=20 return x + y end local a=foo --把函數賦給變量 print(a()) --output: in the function 30
表達式
~=不等于
邏輯運算符說明and邏輯與or邏輯或not邏輯非
local c=nil
local d=0
local e=100
print(c and d) -->打印 nil
print(c and e) -->打印 nil
print(d and e) -->打印 100
print(c or d) -->打印 0
print(c or e) -->打印 100
print(not c) -->打印 true
print(not d) --> 打印 false
在 Lua 中連接兩個字符串,可以使用操作符“..”(兩個點).
print("Hello " .. "World") -->打印 Hello World print(0 .. 1) -->打印 01
控制語句
單個 if 分支 型
x=10 if x > 0 then print("x is a positive number") end
兩個分支 if-else 型
x=10 if x > 0 then print("x is a positive number") else print("x is a non-positive number") end
多個分支 if-elseif-else 型:
score=90 if score==100 then print("Very good!Your score is 100") elseif score >=60 then print("Congratulations, you have passed it,your score greater or equal to 60") --此處可以添加多個elseif else print("Sorry, you do not pass the exam! ") end
for 控制結構
Lua 提供了一組傳統的、小巧的控制結構,包括用于條件判斷的 if 用于迭代的 while、repeat 和 for,本章節主要介紹 for 的使用.
for 數字型
for 語句有兩種形式:數字 for(numeric for) 和范型 for(generic for) 。 數字型 for 的語法如下:
for var=begin, finish, step do
--body
end
實例1:
for i=1, 5 do print(i) end -- output: 1 2 3 4 5
實例2:
for i=1, 10, 2 do
print(i)
end
-- output:
1 3 5 7 9
for 泛型
泛型 for 循環通過一個迭代器(iterator) 函數來遍歷所有值:
-- 打印數組a的所有值 local a={"a", "b", "c", "d"} for i, v in ipairs(a) do print("index:", i, " value:", v) end -- output: index: 1 value: a index: 2 value: b index: 3 value: c index: 4 value: d
lua的入門就到這里,因為lua語法雖少,但細節有很多,不可能花很多時間去研究這個。入個門,遇到問題再去查資料就行了。另外需要說明的是本文大部分內容為復制粘貼于OPenResty 最佳實踐,感謝原作者的開源電子書,讓我獲益匪淺。更多內容請參考:
lua入門教程:http://www.runoob.com/lua/lua-tutorial.html
OPenResty 最佳實踐: https://moonbingbing.gitbooks.io/openresty-best-practices/content/index.html
年來,前端技術日新月異,前端已經不僅僅是網頁,更多的開始由狹義向廣義發展。
先后涌現出了具備后端能力的node,具備移動開發能力的react native,具備游戲渲染能力的cocos2d-js,以及iOS上的熱修復技術JSPatch等等新技術。
咋一看,幾乎各個端都被JavaScript攻陷,大有一統江湖之勢。
究竟,JavaScript如何做到上天入地無所不能?JavaScript真的能一統江湖嗎?
亂世出英雄:JavaScript的誕生故事要從JavaScript的由來說起。
高能瞎扯淡版,正經臉的同學可以忽略
有人的地方就有江湖,有江湖的地方就有紛爭。
故事要從當年的瀏覽器之戰說起。
時間回到1994年,
(→ 那時候我還是個寶寶~ #天真臉#)
景兄弟橫空出世,并自帶神器網景導航,戰斗力爆表,勢如劈竹,瞬時間威震天下。
一出世就武裝到牙齒,武力值這么高還自帶兵器,這個科學嗎?
港真,我也覺得不科學,也許跟熊孩子哪吒、女漢子雅典娜是一個品種吧?
這一切北方的老前輩微軟大濕,都看在眼里,不甘天下盡歸景兄弟這個初出茅廬的毛孩子,大濕積淀多年,潛心修煉一年,終于帶著大殺器IE 1.0出關了,誓于景兄弟爭個高低。
自此景兄弟的網景導航 VS 微軟大濕的IE 的軍備戰爭開始。
景兄弟仔細掂量,微軟大濕財大氣粗,內功深厚,臣妾實在是辦不到啊啊啊啊啊啊。
景兄弟緊急召集門人商議對策,有一門人曰:”以我們微薄之力硬磕,是萬萬使不得的。如今我們,一是宜施行合縱之策,抱大腿,組成聯盟!二是避其鋒芒,出奇招致勝。“
于是景兄弟依照此策略,一方面找到了當時德高為重的另一位前輩SUN,組成了開發者聯盟。
(微軟大濕:握草,聯盟都粗來了,那我是不是得搞個部落?)
另一方面,景兄弟找到了鍛造大師布蘭登,請布大師幫忙升級兵器網景導航,大師就是大師,不費吹灰之力就完成了強化升級,然而布大師突發奇想,本來這是近距離攻擊兵器,要是有多一個遠距離攻擊的能力那豈不是更好?Just do it. 想罷大師就加了一個遠距離攻擊的feature。于是有了自帶遠距離攻擊能力的網景導航2.0。景兄弟一看這么流弊心里甚是歡喜,不過遠距離攻擊的技能叫做LiveScript,感覺不是特別Fashion。特然想到這不是跟SUN前輩聯盟嘛,SUN家的Java正是獨霸武林之時。不如把名字改成跟Java有關,蹭一把東風,蹭點光環。一拍腦袋,JavaScript!!!眾門人一聽:”好好好,JavaScript 流弊炫酷吊炸天!“
果然第一節下半場,景兄弟攜強化過的網景導航2.0 戰個痛快,那是杠杠的!人家一問,你咋還能遠程攻擊,你這個遠程攻擊用的是啥?答曰:JavaScript。“JavaScript,一定是跟SUN家Java是一個系列產品,一定很流弊!”#光環加成,各種膜拜臉#
微軟大濕虧了一場,痛定思痛,也要搞遠程攻擊功能,果然不久,就祭出了同樣帶有遠程攻擊能力的IE 3.0,鑒于景兄弟的遠程攻擊叫做JavaScript,J開頭的感覺應該比較流弊,所以微軟大濕的叫做JScript。
然后戰爭就從地面貼身肉搏戰,開始逐步升級到了遠距離核戰爭。
正所謂,城門失火,殃及池魚。這么打下去苦逼的是搬磚的頁面仔,就是我這種,到處都是雷區,無處下腳。
最后到了1997年,“聯合國安理會秘書長”艾瑪(ECMA)出來調停,多方簽署了“核不擴散條約”,約束各種遠程攻擊武器的使用,這才走上了正軌。
1995年SUN開發了Java技術,這是第一個通用軟件平臺。Java擁有跨平臺、面向對象、泛型編程的特性,廣泛應用于企業級Web應用開發和移動應用開發。Java也伴隨著互聯網的迅猛發展而發展,逐漸成為重要的網絡編程語言。名噪一時。
1994年Netscape公司成立,并推出了自己的瀏覽器的免費版本 Netscape Navigator,很快就占有了瀏覽器市場。到了 1995 年,微軟公司開始加入,并很快發布了自己的 Internet Explorer 1.0。
1995年,當時在Netscape就職的Brendan Eich(布蘭登·艾克),正為Netscape Navigator 2.0瀏覽器開發的一門名為LiveScript的腳本語言,后來Netscape與Sun Microsystems組成的開發聯盟,為了讓這門語言搭上Java這個編程語言“熱詞”,將其臨時改名為“JavaScript”,日后這成為大眾對這門語言有諸多誤解的原因之一。
JavaScript最初受Java啟發而開始設計的,目的之一就是“看上去像Java”,因此語法上有類似之處,一些名稱和命名規范也借自Java。但JavaScript的主要設計原則源自Self和Scheme。JavaScript與Java名稱上的近似,是當時Netscape為了營銷考慮與SUN達成協議的結果。
==> 所以,JavaScript和Java其實沒有半毛錢關系。
JavaScript推出后在瀏覽器上大獲成功,微軟在不久后就為Internet Explorer 3.0瀏覽器推出了JScript,以與處于市場領導地位的Netscape產品同臺競爭。JScript也是一種JavaScript實現,這兩個
JavaScript語言版本在瀏覽器端共存意味著語言標準化的缺失,對這門語言進行標準化被提上了日程,在1997年,由Netscape、SUN、微軟、寶藍等公司組織及個人組成的技術委員會在ECMA(歐洲計算機制造商協會)確定定義了一種名叫ECMAScript的新腳本語言標準,規范名為ECMA-262。JavaScript成為了ECMAScript的實現之一。ECMA-262 第五版,即是ES5。
==> ECMA-262,包括ES5, ES6等是一個標準,JavaScript是ECMAScript的一個實現。
完整的JavaScript實現應該包含三個部分:
在網景導航2.0和IE 3.0出現之后的幾年間,網景和微軟公司不停的發布新版本的瀏覽器,支持更多的新功能。自此拉開了瀏覽器之戰的序幕。這場瀏覽器之戰到現在還在繼續,以下一張圖看清楚過程。
從瀏覽器之戰可以看出,各家瀏覽器比拼的大致兩個方面視覺體驗(渲染排版)和速度(腳本運行)。
==> 所以一個完整的瀏覽器組成,至少包含兩個部分:
補充一個市面常見瀏覽器的內核和JavaScript引擎搭配:
其他JavaScript引擎,Rhino,由Mozilla基金會管理,開放源代碼,完全以Java編寫,可以看做SpiderMonkey的Java版。
注意:webkit不單單只是一個排版引擎,webkit=排版引擎 + JavaScript引擎。
==> 所以,JavaScript是動態語言,它的運行都是基于JavaScript引擎,引擎大都是由靜態語言實現C++、Java、and so on。JavaScript的能力也是由引擎賦予。不管是瀏覽器環境中是window,亦或是node環境中的process,均是由引擎提供。
(番外:Mozilla的人不知道為啥特別喜歡猴子,經常以猴子命名技術,所以看到帶Monkey的,十有八九估計是他們搞的。)
在瀏覽器環境中,DOM、BOM、window對象、setTimeout/setInterval,alert,console等方法均不是JavaScript自身具備的能力,而是瀏覽器native實現,然后通過JavaScript引擎注入到JS運行的全局上下文中,供JS使用。
鑒別方式,在調試器console中打出來,帶有[native code]的即是:
講道理:
JavaScript運行 → 依賴于JavaScript引擎 ← 瀏覽器集成了JavaScript引擎,同時通過JavaScript引擎注入native代碼工JS腳本使用
發散一下思維,只要有JavaScript引擎,就能運行JS腳本,不管有沒有瀏覽器!只是缺少瀏覽器提供的alert,window等方法。
既然瀏覽器可以往JavaScript引擎中注入代碼,賦予JS腳本在網頁中特殊的能力,同理我們可以自己集成JavaScript引擎,自己定義自己的方法往JavaScript引擎中注入,賦予JS更多更強的自定義能力!
注入的關鍵是:值類型相互對應,Obj映射class的一個實例,function映射一個句柄或者引用
JavaScript內部,所有數字都是以64位浮點數形式儲存,即使整數也是如此
這就是說,在JavaScript語言的底層,根本沒有整數,所有數字都是小數(64位浮點數)。容易造成混淆的是,某些運算只有整數才能完成,此時JavaScript會自動把64位浮點數,轉成32位整數,然后再進行運算。由于浮點數不是精確的值,所以涉及小數的比較和運算要特別小心。盡量避免使用JavaScript做精準計算和密集計算。
根據國際標準IEEE 754,JavaScript浮點數的64個二進制位,從最左邊開始,是這樣組成的。
第1位:符號位,0表示正數,1表示負數
第2位到第12位:儲存指數部分
第13位到第64位:儲存小數部分(即有效數字)
符號位決定了一個數的正負,指數部分決定了數值的大小,小數部分決定了數值的精度。
IEEE 754規定,有效數字第一位默認總是1,不保存在64位浮點數之中。也就是說,有效數字總是1.xx…xx的形式,其中xx..xx的部分保存在64位浮點數之中,最長可能為52位。因此,JavaScript提供的有效數字最長為53個二進制位(64位浮點的后52位+有效數字第一位的1)。
內部表現公式:(-1)^符號位 1.xx…xx 2^指數位
精度最多只能到53個二進制位,這意味著,絕對值小于2的53次方的整數,即-(253-1)到253-1,都可以精確表示。
而大部分的后端語言,C++、Java、Python等的long型都是可以支持到64位,因此long型數據從后端語言傳給JavaScript會發生低位截斷。遇到這種情況一般使用String處理,如需要在JavaScript中做long型計算,需要自行實現計算器。
有了自行往JavaScript引擎中注入的想法,接下來就是分析可行性。
大部分是JavaScript引擎是使用C++編寫,如果自己的程序使用的是C++可以很方便的進行注入,如果是OC,可以使用OC和C++混編的形式。
其他語言怎么破?
要在一門靜態語言上與動態語言JavaScript相互調用,最便捷的方式是找到一個這門語言實現的JavaScript引擎(開源),直接進行集成,注入。如果沒有,則需要使用多一層橋接,把這門語言的接口暴露給C++,再由C++實現的JavaScript引擎將接口注入供JavaScript使用。
服務端集成思路&實踐:
我們都知道nodeJS,但是nodeJS的運行依賴于Google的V8 引擎,V8是C++實現,底層使用C++實現底層功能,比如網絡,數據庫IO,對外暴露一個構造器接口注入到上下文中,注意此處暴露的只是一個構造器接口而不是一個創建完的實例。然后實現了一個require的hook函數。當使用require加載一個JS模塊時,跟網頁中使用AMD 的require并無異樣,當使用require加載系統庫,既是C++的模塊時,會調用暴露出來的構造器接口,得到一個實例對象。不管是裝載JS模塊還是裝載C++模塊,得到的都可以看做是一個Module Object,node會將裝載完的模塊緩存到binding_cache中,下次在別處的代碼中使用require裝載模塊時,就會先去binding_cache中查找,如果找到了則返回該module object,如果沒找到再執行上面的裝載流程。
這就是node的基本原理:C++封裝底層操作,通過V8注入,使得JS腳本有網絡和IO能力
以上說到的幾個都是C++層面的應用,那么經典的Java怎么玩?是不是Java就必須是靜態語言的玩法,沒有辦法像C++之類的,可以使用JS的動態特性?
當然不是。這個時候,我們需要說起前面介紹過的一個JS引擎 Rhino,Rhino是完全由Java編寫,可想而知,Rhino幾乎就是為Java應用而生的。
用法是這樣:
首先在我們的Java應用中集成Rhino;
所有的IO操作,網絡操作等,都封裝成service,并提供增刪改查,setter && getter等多種方法
通過spring,把這些service bean注入到Rhino中;
把業務邏輯寫到JS代碼中,JS代碼調用多個已注入的Java service處理業務邏輯,拼裝數據返回!
好處:修改業務邏輯不需要修改Java代碼,也就是不需要重新編譯和部署,只需要刷新下跑在Rhino中的JS代碼即可。以往Java應用的一個痛點是部署,需要重新編譯,打包,部署重啟服務器,現在以這種形式開發,可以達到服務端的熱更新和熱部署。既可以享有Java服務的穩定性和可靠性,又可以享有JS的靈活性。
這種技術和用法在差不多十年前就有過,前EMC的工程師基于EMC著名的商業產品Documentum,設計了一套Java開源的中小企業CMS系統Alfresco,在該系統中實現了這種技術,這種技術基于spring,叫做spring-surf,做了一個膠水層。可以看做小十年前的node吧。
Demo,使用spring-surf框架的系統中一個webscript模塊
categorynode.get.xml定義URL攔截器和權限控制;
.get指明是處理GET請求,RESTful;
在categorynode.get.js中調用已注入的Java Bean處理業務邏輯;
若為網頁請求返回.html.ftl,若為Ajax,返回.json.ftl;
(此處配套使用的是FreeMarker模板引擎)
==> categorynode.get.desc.xml
==> categorynode.get.js
==> categorynode.get.html.ftl
==> categorynode.get.json.ftl
React Native目前也是異常火爆,RN程序的運行依賴于Facebook的RN框架。在iOS、Android的模擬器或是真機上,React Native使用的是JavaScriptCore引擎,也就是Safari所使用的JavaScript引擎。但是在iOS上JavaScriptCore并沒有使用即時編譯技術(JIT),因為在iOS中應用無權擁有可寫可執行的內存頁(因而無法動態生成代碼),在安卓上,理論上是可以使用的。JavaScriptCore引擎也是使用C++編寫,在iOS和安卓中,JavaScriptCore都做了一層封裝,可以無須關心引擎和系統橋接的那一層。iOS/Android系統通過JavaScriptCore引擎將定制好的各種原生組件注入,如:listview,text等。
cocos2dx是游戲開發中非常常用的游戲渲染引擎,有一系列的產品,如:cocos2dx(C++),cocos2d-lua(lua), cocos2d-js(JavaScript)等多個產品。其中最新退出的是cocos2dx的JS版本的cocos2d-js,編寫游戲渲染特效代碼相比于C++和lua非常方便。對于做需要經常更新的渲染場景,C++是靜態語言,每次修改都需要重新編譯才能運行,顯然是不合適的。自然也就想到了腳本語言,lua和js,兩者有些類似,都是動態語言,只需要集成一個運行引擎,提供一個運行的容器即可運行,同時通過引擎注入底層方法供腳本調用即可。lua好處是精簡,語法精簡,引擎頁很小很精簡,所以不可避免的代碼量會比js多,同時學習成本比較高。js的好處是有ECMAScrtpt的核心,語法比較豐富,同時有支持一些高級屬性。在cocos2d-js中,cocos2dx(C++)集成了SpiderMonkey(C++)作為JS運行引擎,中間做了一個膠水層既是JS Binding,通過引擎注入了一個cc的全局對象,映射的是底層C++的一個單例C++實例。表面上寫的是JS代碼,實際上操作的是底層的C++。cocos2d-js是代碼可以運行在多種環境中,當運行的網頁環境中時,使用的是cocos2d-html5引擎,底層操作的是canvas;當運行在客戶端上時,使用的是cocos2dx引擎,底層操作的是C++,再由C++去操控openGL做繪制和渲染。提供相同的API,對開發者幾乎是透明無差異的,開發者只需要關注實現效果即可。達到一套代碼,多端運行(網頁端,客戶端)。
JSPatch是目前比較流行的iOS上的熱修復技術,JSPatch 能做到通過 JS 調用和改寫 OC 方法最根本的原因是 Objective-C 是動態語言,OC 上所有方法的調用/類的生成都通過 Objective-C Runtime 在運行時進行,我們可以通過類名/方法名反射得到相應的類和方法。JSPatch 的基本原理就是:JS 傳遞字符串給 OC,OC 通過 Runtime 接口調用和替換 OC 方法。
關鍵技術之一是 JS 和 OC 之間的消息互傳。JSPatch里包含了,一個JS引擎JavaScriptCore(Safari,React Native用的同款)。用到了 JavaScriptCore 的接口,OC 端在啟動 JSPatch 引擎時會創建一個 JSContext 實例,JSContext 是 JS 代碼的執行環境,可以給 JSContext 添加方法,JS 就可以直接調用這個方法。本質上就是通過JavaScriptCore引擎注入,暴露OC的方法供JS調用來實現動態修改OC的反射。
Demo,iOS熱更新,熱修復:
集成JavaScriptCore引擎;
通過引擎,橋接JS和OC;
通過JS修改OC反射。
詳細的JSPatch技術介紹請移步:https://github.com/bang590/JSPatch/wiki
關于JavaScript引擎:
在iOS 或 android 上能夠運行的JavaScript 引擎有4個:JavaScriptCore,SpiderMonkey,V8,Rhino。下面這個表格展示各個引擎在iOS 和 Android 的兼容性。
因為iOS平臺不支持JIT即時編譯,而V8只有JIT模式,所以V8無法在iOS平臺使用(越獄設備除外,想體驗iOS JIT的同學可以自行越獄)。
所以,目前可以做到橫跨iOS和Android雙平臺的JS引擎,只有兩款,即是SpiderMonkey和JavaScriptCore。
JavaScript引擎會受很多東西影響,比如交叉編譯器的版本、引擎的版本和操作系統的種類等。
至于如何選擇,可以參考:《Part I: How to Choose a JavaScript Engine for iOS and Android Development》
至此,JavaScript從立足于前端,到征戰全端的逆襲之路,可以總結為“攜引擎以令天下”。
不足之處,還請各位看官輕拍~
bang590/JSPatch中問參考文檔
Cocos2d-JS | Cocos2d-x官方參考文檔
Alfresco官方參考文檔
《Browser Wars: The End or Just the Beginning?》
《Part I: How to Choose a JavaScript Engine for iOS and Android Development》
《React Native 從入門到源碼》
兩個減號是單行注釋
--
--[[ 多行注釋 多行注釋 --]]
Lua 中有 8 個基本類型分別為:nil、boolean、number、string、userdata、function、thread和 table。
> type(a) nil > type(a)==nil false > type(a)=='nil' true > type(type(a)) string
boolean 類型只有兩個可選值:true和 false,Lua 把false和nil看作是”假”,其他的都為”真”。
Lua 默認只有一種 number 類型 :double(雙精度)類型。
字符串由一對雙引號或單引號來表示,也可以用 2 個方括號 “[[]]” 來表示”一塊”字符串
> html=[[ >> <html> >> <head></head> >> <body> >> <a >Gitlib</a> >> </body> >> </html> >> ]] > print(html)
在 Lua 中,函數是被看作是一種特殊的變量,函數可以存在變量里。
在 Lua 里,最主要的線程是協同程序(coroutine)。它跟線程(thread)差不多,擁有自己獨立的棧、局部變量和指令指針,可以跟其他協同程序共享全局變量和其他大部分東西。
線程跟協程的區別:線程可以同時多個運行,而協程任意時刻只能運行一個,并且處于運行狀態的協程只有被掛起(suspend)時才會暫停。
userdata 是一種用戶自定義數據,用于表示一種由應用程序或 C/C++ 語言庫所創建的類型,可以將任意 C/C++ 的任意數據類型的數據(通常是 struct 和 指針)存儲到 Lua 變量中調用。
> function joke() >> c=5 -- 全局變量 >> local d=6 -- 局部變量 >> end > > joke() > print(c,d) -- 輸出結果,在函數中定義的變量依然是全局變量 5 nil -- 多個變量賦值 > a, b, c=0, 1 > print(a,b,c) 0 1 nil
注意:Lua僅支持break跳出循環,不支持continue;
while(condition) do statements end
-- 數值 for var=min,max,step do statements end -- table進行for循環,ipairs為迭代器方法 a={"one", "two", "three"} for i, v in ipairs(a) do print(i, v) end
repeat statements until( condition
if( 布爾表達式 1) then --[ 在布爾表達式 1 為 true 時執行該語句塊 --] elseif( 布爾表達式 2) then --[ 在布爾表達式 2 為 true 時執行該語句塊 --] else --[ 如果以上布爾表達式都不為 true 則執行該語句塊 --] end
function add(...) local s=0 for i, v in ipairs{...} do -- {...} 表示一個由所有變長參數構成的數組 s=s + v end return s end
-- 文件名為 module.lua -- 定義一個名為 module 的模塊 module={} -- 定義一個常量 module.constant="這是一個常量" -- 定義一個函數 function module.func() io.write("這是一個公有函數!\n") end local function func2() print("這是一個私有函數!") end return module
Lua提供了一個名為require()的函數用來加載模塊,例如:
require("<模塊名>")
Lua提供了元表(Metatable)來改變table的行為,有點類似于Javascript中的原型鏈,還為每個行為關聯了對應的元方法。例如使用元表,可以定義Lua如何計算兩個table的相加操作a+b,當Lua試圖對兩個表進行相加時,先檢查兩者之一是否有元表,之后檢查是否有一個叫__add的字段,若找到,則調用對應的值,__add等字段,其對應的值(往往是一個函數或是table)就是”元方法“。
還有其他各種元方法:
基于元表的特性(繼承),可以實現Lua面向對象編程。
Lua 協同程序(coroutine)與線程比較類似:擁有獨立的堆棧,獨立的局部變量,獨立的指令指針,同時又與其它協同程序共享全局變量和其它大部分東西。
co=coroutine.create( function(i) print(i); end ) coroutine.resume(co, 1) -- 輸出:1
io方法稱為簡單模式,一次只能處理一個輸入文件和輸出文件,file句柄形式則可以同時操作多個文件。
1assert(type(a)=="number", "a 不是一個數字")
assert首先檢查第一個參數,若沒問題,assert不做任何事情;否則,assert以第二個參數作為錯誤信息拋出。
error (message [, level])
終止正在執行的函數,并返回message的內容作為錯誤信息。
Lua中處理錯誤,可以使用函數pcall(protected call)來包裝需要執行的代碼。
pcall接收一個函數和要傳遞給后者的參數,并執行,執行結果:有錯誤、無錯誤;返回值true或者或false, errorinfo。
if pcall(function_name, ….) then -- 沒有錯誤 else -- 一些錯誤 end
*請認真填寫需求信息,我們會在24小時內與您取得聯系。