摘要:對于正常結束,將返回,并接上協程主函數的返回值。當錯誤發生時,將返回與錯誤消息。通過調用使協程暫停執行,讓出執行權。通用形式的通過一個叫作迭代器的函數工作。
Lua 是一門強大、輕量的嵌入式腳本語言,可供任何需要的程序使用。Lua 沒有 "main" 程序的概念: 它只能 嵌入 一個宿主程序中工作.宿主程序可以調用函數執行一小段 Lua 代碼,可以讀寫 Lua 變量,可以注冊 C 函數讓 Lua 代碼調用。
Lua 是一門動態類型語言。 這意味著變量沒有類型;只有值才有類型。
Lua 中所有的值都是 一等公民。 這意味著所有的值均可保存在變量中、 當作參數傳遞給其它函數、以及作為返回值。
文檔:5.3:http://cloudwu.github.io/lua5...
5.1:http://book.luaer.cn/
Lua 中有八種基本類型: nil、boolean、number、string、function、userdata、 thread 和 table。
Nil 是值 nil 的類型.和Python中None,Java中null類似。
Boolean 是 false 與 true 兩個值的類型。與其他語言不通的是nil 和 false 都會導致條件判斷為假; 而其它任何值都表示為真。而其它語言判斷比如0時為假,但lua為真。
Number 代表了整數和實數(浮點數)。 它也按需作自動轉換
String 表示一個不可變的字節序列。Lua 的字符串與編碼無關; 它不關心字符串中具體內容。
Lua 可以調用(以及操作)用 Lua 或 C 編寫的函數。 這兩種函數有統一類型 function。
userdata 類型允許將 C 中的數據保存在 Lua 變量中。 用戶數據類型的值是一個內存塊, 有兩種用戶數據: 完全用戶數據 ,指一塊由 Lua 管理的內存對應的對象; 輕量用戶數據 ,則指一個簡單的 C 指針。 用戶數據在 Lua 中除了賦值與相等性判斷之外沒有其他預定義的操作。 通過使用 元表 ,程序員可以給完全用戶數據定義一系列的操作。 你只能通過 C API 而無法在 Lua 代碼中創建或者修改用戶數據的值, 這保證了數據僅被宿主程序所控制。
thread 類型表示了一個獨立的執行序列,被用于實現協程 。 Lua 的線程與操作系統的線程毫無關系。 Lua 為所有的系統,包括那些不支持原生線程的系統,提供了協程支持。
table 是一個關聯數組, 也就是說,這個數組不僅僅以數字做索引,除了 nil 和 NaN 之外的所有 Lua 值 都可以做索引。(Not a Number 是一個特殊的數字,它用于表示未定義或表示不了的運算結果,比如 0/0。) 表可以是 異構 的; 也就是說,表內可以包含任何類型的值( nil 除外)。
表是 Lua 中唯一的數據結構, 它可被用于表示普通數組、序列、符號表、集合、記錄、圖、樹等等。 對于記錄,Lua 使用域名作為索引。 語言提供了 a.name 這樣的語法糖來替代 a["name"]。
我們使用 序列 這個術語來表示一個用 {1..n} 的正整數集做索引的表.注意:lua中索引從1開始,而非0
和索引一樣,表中每個域的值也可以是任何類型。 需要特別指出的是:既然函數是一等公民,那么表的域也可以是函數。 這樣,表就可以攜帶 方法 了。
表、函數、線程、以及完全用戶數據在 Lua 中被稱為 對象: 變量并不真的 持有 它們的值,而僅保存了對這些對象的 引用。 賦值、參數傳遞、函數返回,都是針對引用而不是針對值的操作, 這些操作均不會做任何形式的隱式拷貝。
類型判斷庫函數 type 用于以字符串形式返回給定值的類型。
錯誤處理由于 Lua 是一門嵌入式擴展語言,其所有行為均源于宿主程序中 C 代碼對某個 Lua 庫函數的調用。 (多帶帶使用 Lua 時,lua 程序就是宿主程序。) 所以,在編譯或運行 Lua 代碼塊的過程中,無論何時發生錯誤, 控制權都返回給宿主,由宿主負責采取恰當的措施(比如打印錯誤消息)。
可以在 Lua 代碼中調用 error 函數來顯式地拋出一個錯誤。 如果你需要在 Lua 中捕獲這些錯誤, 可以使用 pcall 或 xpcall 在 保護模式 下調用一個函數。
無論何時出現錯誤,都會拋出一個攜帶錯誤信息的 錯誤對象 (錯誤消息),這是一個字符串對象。
使用 xpcall 或 lua_pcall 時, 你應該提供一個 消息處理函數 用于錯誤拋出時調用。 該函數需接收原始的錯誤消息,并返回一個新的錯誤消息。
Lua 中的每個值都可以有一個 元表。 這個 元表 就是一個普通的 Lua 表, 它用于定義原始值在特定操作下的行為。元表中的鍵對應著不同的 事件 名; 鍵關聯的那些值被稱為 元方法。
你可以用 getmetatable 函數 來獲取任何值的元表。
使用 setmetatable 來替換一張表的元表。在 Lua 中,你不可以改變表以外其它類型的值的元表 (除非你使用調試庫); 若想改變這些非表類型的值的元表,請使用 C API。
表和完全用戶數據有獨立的元表 (當然,多個表和用戶數據可以共享同一個元表)。 其它類型的值按類型共享元表; 也就是說所有的數字都共享同一個元表, 所有的字符串共享另一個元表等等。
元表決定了一個對象在數學運算、位運算、比較、連接、 取長度、調用、索引時的行為。 元表還可以定義一個函數,當表對象或用戶數據對象在垃圾回收時調用它。
其它具體見文檔。。。。
Lua 采用了自動內存管理。Lua 實現了一個增量標記-掃描收集器。
垃圾收集元方法:
你可以為表設定垃圾收集的元方法,對于完全用戶數據, 則需要使用 C API 。 該元方法被稱為 終結器。 終結器允許你配合 Lua 的垃圾收集器做一些額外的資源管理工作 (例如關閉文件、網絡或數據庫連接,或是釋放一些你自己的內存)。
如果要讓一個對象(表或用戶數據)在收集過程中進入終結流程, 你必須 標記 它需要觸發終結器。 當你為一個對象設置元表時,若此刻這張元表中用一個以字符串 "__gc" 為索引的域,那么就標記了這個對象需要觸發終結器。
調用函數 coroutine.create 可創建一個協程。 其唯一的參數是該協程的主函數。 create 函數只負責新建一個協程并返回其句柄 (一個 thread 類型的對象); 而不會啟動該協程。
調用 coroutine.resume 函數執行一個協程。
協程的運行可能被兩種方式終止: 正常途徑是主函數返回 (顯式返回或運行完最后一條指令); 非正常途徑是發生了一個未被捕獲的錯誤。 對于正常結束, coroutine.resume 將返回 true, 并接上協程主函數的返回值。 當錯誤發生時, coroutine.resume 將返回 false 與錯誤消息。
通過調用 coroutine.yield 使協程暫停執行,讓出執行權。 協程讓出時,對應的最近 coroutine.resume 函數會立刻返回,即使該讓出操作發生在內嵌函數調用中 (即不在主函數,但在主函數直接或間接調用的函數內部)。 在協程讓出的情況下, coroutine.resume 也會返回 true, 并加上傳給 coroutine.yield 的參數。 當下次重啟同一個協程時, 協程會接著從讓出點繼續執行。
與 coroutine.create 類似, coroutine.wrap 函數也會創建一個協程。 不同之處在于,它不返回協程本身,而是返回一個函數。 調用這個函數將啟動該協程。 傳遞給該函數的任何參數均當作 coroutine.resume 的額外參數。 coroutine.wrap 返回 coroutine.resume 的所有返回值,除了第一個返回值(布爾型的錯誤碼)。 和 coroutine.resume 不同, coroutine.wrap 不會捕獲錯誤; 而是將任何錯誤都傳播給調用者。
下面的代碼展示了一個協程工作的范例:
function foo (a) print("foo", a) return coroutine.yield(2*a) end co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) local r, s = coroutine.yield(a+b, a-b) print("co-body", r, s) return b, "end" end) print("main", coroutine.resume(co, 1, 10)) print("main", coroutine.resume(co, "r")) print("main", coroutine.resume(co, "x", "y")) print("main", coroutine.resume(co, "x", "y")) 當你運行它,將產生下列輸出: co-body 1 10 foo 2 main true 4 co-body r main true 11 -9 co-body x y main true 10 end main false cannot resume dead coroutine
你也可以通過 C API 來創建及操作協程: 參見函數 lua_newthread, lua_resume, 以及 lua_yield。
語言定義Lua 語言的格式自由。 它會忽略語法元素(符記)間的空格(包括換行)和注釋, 僅把它們看作為名字和關鍵字間的分割符。
Lua 語言對大小寫敏感。
字面串 可以用單引號或雙引號括起。 字面串內部可以包含下列 C 風格的轉義串。
轉義串 "z" 會忽略其后的一系列空白符,包括換行; 它在你需要對一個很長的字符串常量斷行為多行并希望在每個新行保持縮進時非常有用。
對于用 UTF-8 編碼的 Unicode 字符,你可以用 轉義符 u{XXX} 來表示
代碼注釋:
--這是行注釋 --[[這是塊 注釋]]變量:
Lua 中有三種變量: 全局變量、局部變量和表的域。
所有沒有顯式聲明為局部變量的變量名都被當做全局變量。 這一點倒是和js很相似。
全局變量 x = 1234 的賦值等價于 _ENV.x = 1234
局部變量 local namelist [‘=’ explist] 比如 local name="xbynet"
每個語句結尾的分號(;)是可選的,但如果同一行有多個語句最好用;分開
-- file "lib1.lua" function norm (x, y) local n2 = x^2 + y^2 return math.sqrt(n2) end function twice (x) return 2*x end
在交互模式下:
> lua -i > dofile("lib1.lua") -- load your library > n = norm(3.4, 1.0) > print(twice(n)) --> 7.0880180586677
-i和dofile在調試或者測試Lua代碼時是很方便的。
命令行方式
> lua -e "print(math.sin(12))" --> -0.53657291800043
全局變量arg存放Lua的命令行參數。
prompt> lua script a b c
在運行以前,Lua使用所有參數構造arg表。腳本名索引為0,腳本的參數從1開始增加。腳本前面的參數從-1開始減少。
if, while, and repeat 這些控制結構符合通常的意義,而且也有類似的語法:
while exp do block end repeat block until exp if exp then block elseif exp then block else block end
for 有兩種形式:一種是數字形式,另一種是通用形式。
數值for循環:
for var=exp1,exp2,exp3 do loop-part end
for將用exp3作為step從exp1(初始值)到exp2(終止值),執行loop-part。其中exp3可以省略,默認step=1
有幾點需要注意:
三個表達式只會被計算一次,并且是在循環開始前。
for i=1,f(x) do
print(i)
end
for i=10,1,-1 do
print(i)
end
第一個例子f(x)只會在循環前被調用一次。
通用形式的 for 通過一個叫作 迭代器 的函數工作。 每次迭代,迭代器函數都會被調用以產生一個新的值, 當這個值為 nil 時,循環停止。
for var_1, ···, var_n in explist do block end -- print all values of array "a" for i,v in ipairs(a) do print(v) end 再看一個遍歷表key的例子: -- print all keys of table "t" for k in pairs(t) do print(k) end
控制結構中的條件表達式可以返回任何值。 false 與 nil 兩者都被認為是假。 所有不同于 nil 與 false 的其它值都被認為是真 (特別需要注意的是,數字 0 和空字符串也被認為是真)。
有break,但是沒有continue
return 被用于從函數或是代碼塊(其實它就是一個函數) 中返回值。 函數可以返回不止一個值。
return 只能被寫在一個語句塊的最后一句。 如果你真的需要從語句塊的中間 return, 你可以使用顯式的定義一個內部語句塊, 一般寫作 do return end。 可以這樣寫是因為現在 return 成了(內部)語句塊的最后一句了。
Lua語法要求break和return只能出現在block的結尾一句(也就是說:作為chunk的最后一句,或者在end之前,或者else前,或者until前),例如:
local i = 1 while a[i] do if a[i] == v then break end i = i + 1 end
有時候為了調試或者其他目的需要在block的中間使用return或者break,可以顯式的使用do..end來實現:
function foo () return --<< SYNTAX ERROR -- "return" is the last statement in the next block do return end -- OK ... -- statements not reached end表達式
數學運算操作符
+: 加法 -: 減法 *: 乘法 /: 浮點除法 //: 向下取整除法 %: 取模 ^: 乘方 -: 取負
比較操作符
==: 等于 ~=: 不等于 <: 小于 >: 大于 <=: 小于等于 >=: 大于等于
注意:不等于是~=,而不是!=
這些操作的結果不是 false 就是 true。
等于操作 (==)先比較操作數的類型。 如果類型不同,結果就是 false。 否則,繼續比較值。 字符串按一般的方式比較。 數字遵循二元操作的規則
表,用戶數據,以及線程都按引用比較: 只有兩者引用同一個對象時才認為它們相等。
你可以通過使用 "eq" 元方法來改變 Lua 比較表和用戶數據時的方式。
邏輯操作符
Lua 中的邏輯操作符有 and, or,以及 not。
和控制結構一樣, 所有的邏輯操作符把 false 和 nil 都作為假, 而其它的一切都當作真。
字符串連接
Lua 中字符串的連接操作符寫作兩個點("..")。 如果兩個操作數都是字符串或都是數字, 連接操作將以中提到的規則把其轉換為字符串。 否則,會調用元方法 __concat
多行字符串
還可以使用[[...]]表示字符串。這種形式的字符串可以包含多行
page = [[ qwwqwq adas ss ]]
取長度操作符
取長度操作符寫作一元前置符 #。 字符串的長度是它的字節數(就是以一個字符一個字節計算的字符串長度)。而Python是內置的len()函數,Java和JS都是字符串函數.length()
程序可以通過 __len 元方法來修改對字符串類型外的任何值的取長度操作行為。
表構造子是一個構造表的表達式。 每次構造子被執行,都會構造出一張新的表。 構造子可以被用來構造一張空表, 也可以用來構造一張表并初始化其中的一些域。
構造器是創建和初始化表的表達式。表是Lua特有的功能強大的東西。最簡單的構造函數是{},用來創建一個空表。可以直接初始化數組:
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
Lua將"Sunday"初始化days[1](第一個元素索引為1),用"Monday"初始化days[2]...
如果想初始化一個表作為record使用可以這樣:
a = {x=0, y=0} <--> a = {}; a.x=0; a.y=0
不管用何種方式創建table,我們都可以向表中添加或者刪除任何類型的域,構造函數僅僅影響表的初始化。
w = {x=0, y=0, label="console"} x = {sin(0), sin(1), sin(2)} w[1] = "another field" x.f = w print(w["x"]) --> 0 print(w[1]) --> another field print(x.f[1]) --> another field w.x = nil -- remove field "x"
值得注意的是:w.x = nil -- remove field "x"
在構造函數中域分隔符逗號(",")可以用分號(";")替代,通常我們使用分號用來分割不同類型的表元素。
{x=10, y=45; "one", "two", "three"}
舉個例子:
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
等價于
do local t = {} t[f(1)] = g t[1] = "x" -- 1st exp t[2] = "y" -- 2nd exp t.x = 1 -- t["x"] = 1 t[3] = f(x) -- 3rd exp t[30] = 23 t[4] = 45 -- 4th exp a = t end
如果表單中最后一個域的形式是 exp , 而且其表達式是一個函數調用或者是一個可變參數, 那么這個表達式所有的返回值將依次進入列表
函數函數定義
function f () body end local function f () body end
當一個函數被調用, 如果函數并非一個 可變參數函數, 即在形參列表的末尾注明三個點 ("..."), 那么實參列表就會被調整到形參列表的長度。
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end
下面看看實參到形參數以及可變長參數的映射關系:
CALL PARAMETERS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 g(3) a=3, b=nil, ... --> (nothing) g(3, 4) a=3, b=4, ... --> (nothing) g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 g(5, r()) a=5, b=1, ... --> 2 3
冒號 語法可以用來定義 方法, 就是說,函數可以有一個隱式的形參 self。 因此,如下語句
function t.a.b.c:f (params) body end
是這樣一種寫法的語法糖
t.a.b.c.f = function (self, params) body end
Lua函數可以返回多個結果值
function maximum (a) local mi = 1 -- maximum index local m = a[mi] -- maximum value for i,val in ipairs(a) do if val > m then mi = i m = val end end return m, mi end print(maximum({8,10,23,12,5})) --> 23 3
Lua總是調整函數返回值的個數以適用調用環境,當作為獨立的語句調用函數時,所有返回值將被忽略
第一,當作為表達式調用函數時,有以下幾種情況:
當調用作為表達式最后一個參數或者僅有一個參數時,根據變量個數函數盡可能多地返回多個值,不足補nil,超出舍去。
其他情況下,函數調用僅返回第一個值(如果沒有返回值為nil)
第二,函數調用作為函數參數被調用時,和多值賦值是相同。
第三,函數調用在表構造函數中初始化時,和多值賦值時相同。
可變參數與命名參數
printResult = "" function print(...) for i,v in ipairs(arg) do printResult = printResult .. tostring(v) .. " " end printResult = printResult .. " " end
命名參數用表來作為參數傳遞。
可見性規則Lua 語言有詞法作用范圍。 變量的作用范圍開始于聲明它們之后的第一個語句段, 結束于包含這個聲明的最內層語句塊的最后一個非空語句。
x = 10 -- 全局變量 do -- 新的語句塊 local x = x -- 新的一個 "x", 它的值現在是 10 print(x) --> 10 x = x+1 do -- 另一個語句塊 local x = x+1 -- 又一個 "x" print(x) --> 12 end print(x) --> 11 end print(x) --> 10 (取到的是全局的那一個)
局部變量可以被在它的作用范圍內定義的函數自由使用。 當一個局部變量被內層的函數中使用的時候, 它被內層函數稱作 上值,或是 外部局部變量。
注意,每次執行到一個 local 語句都會定義出一個新的局部變量。 看看這樣一個例子:
a = {} local x = 20 for i=1,10 do local y = 0 a[i] = function () y=y+1; return x+y end end
這個循環創建了十個閉包(這指十個匿名函數的實例)。 這些閉包中的每一個都使用了不同的 y 變量, 而它們又共享了同一份 x。
C API接口由于,目前關注重點在于簡單的redis與Lua及nginx與lua交互,故而暫時略去此部分學習。。。
標準庫所有的庫都是直接用 C API 實現的,并以分離的 C 模塊形式提供。 目前,Lua 有下列標準庫:
基礎庫
協程庫
包管理庫
字符串控制
基礎 UTF-8 支持
表控制
數學函數
輸入輸出
操作系統庫
調試庫
(只列出一些個人認為對初學者常用的)
assert (v [, message])
如果其參數 v 的值為假(nil 或 false), 它就調用 error; 否則,返回所有的參數。 在錯誤情況時, message 指那個錯誤對象; 如果不提供這個參數,參數默認為 "assertion failed!" 。
dofile ([filename])
打開該名字的文件,并執行文件中的 Lua 代碼塊。
error (message [, level])
中止上一次保護函數調用, 將錯誤對象 message 返回。level 參數指明了怎樣獲得出錯位置。 對于 level 1 (默認值),出錯位置指 error 函數調用的位置。 Level 2 將出錯位置指向調用 error的函數的函數;以此類推。 傳入 level 0 可以避免在消息前添加出錯位置信息。
_G
一個全局變量(非函數), 內部儲存有全局環境。 Lua 自己不使用這個變量; 改變這個變量的值不會對任何環境造成影響,反之亦然。
_VERSION
一個包含有當前解釋器版本號的全局變量(并非函數)。 當前這個變量的值為 "Lua 5.3"。
getmetatable (object)
如果 object 不包含元表,返回 nil 。 否則,如果在該對象的元表中有 "__metatable" 域時返回其關聯值, 沒有時返回該對象的元表。
ipairs (t)
以下代碼for i,v in ipairs(t) do body end
將迭代鍵值對(1,t[1]) ,(2,t[2]), ... ,直到第一個空值。
pairs (t)
for k,v in pairs(t) do body end
能迭代表 t 中的所有鍵值對。
load (chunk [, chunkname [, mode [, env]]])
加載一個代碼塊。
如果 chunk 是一個字符串,代碼塊指這個字符串。 如果 chunk 是一個函數, load 不斷地調用它獲取代碼塊的片斷。 每次對 chunk 的調用都必須返回一個字符串緊緊連接在上次調用的返回串之后。 當返回空串、nil、或是不返回值時,都表示代碼塊結束。
如果沒有語法錯誤, 則以函數形式返回編譯好的代碼塊; 否則,返回 nil 加上錯誤消息。
如果結果函數有上值, env 被設為第一個上值。 若不提供此參數,將全局環境替代它。
chunkname 在錯誤消息和調試消息中,用于代碼塊的名字。 如果不提供此參數,它默認為字符串chunk 。
字符串 mode 用于控制代碼塊是文本還是二進制(即預編譯代碼塊)。 它可以是字符串 "b" (只能是二進制代碼塊), "t" (只能是文本代碼塊), 或 "bt" (可以是二進制也可以是文本)。 默認值為 "bt"。
loadfile ([filename [, mode [, env]]])
和 load 類似, 不過是從文件 filename 或標準輸入(如果文件名未提供)中獲取代碼塊。
next (table [, index])
運行程序來遍歷表中的所有域。 第一個參數是要遍歷的表,第二個參數是表中的某個鍵。 next 返回該鍵的下一個鍵及其關聯的值。 特別指出,你可以用 next(t) 來判斷一張表是否是空的。
pcall (f [, arg1, ···])
傳入參數,以 保護模式 調用函數 f 。 這意味著 f 中的任何錯誤不會拋出; 取而代之的是,pcall 會將錯誤捕獲到,并返回一個狀態碼。 第一個返回值是狀態碼(一個布爾量), 當沒有錯誤時,其為真。 此時,pcall 同樣會在狀態碼后返回所有調用的結果。 在有錯誤時,pcall 返回 false 加錯誤消息。
xpcall (f, msgh [, arg1, ···])
這個函數和 pcall 類似。 不過它可以額外設置一個消息處理器 msgh。
print (···)
接收任意數量的參數,并將它們的值打印到 stdout。 它用 tostring 函數將每個參數都轉換為字符串。 print 不用于做格式化輸出。完整的對輸出的控制,請使用 string.format 以及 io.write。
tostring (v)
可以接收任何類型,它將其轉換為人可閱讀的字符串形式。
select (index, ···)
如果 index 是個數字, 那么返回參數中第 index 個之后的部分; 負的數字會從后向前索引(-1 指最后一個參數)。 否則,index 必須是字符串 "#", 此時 select 返回參數的個數。
tonumber (e [, base])
如果調用的時候沒有 base, tonumber 嘗試把參數轉換為一個數字。
type (v)
類型判斷, 函數可能的返回值有 "nil" (一個字符串,而不是 nil 值), "number", "string", "boolean", "table", "function", "thread", "userdata"。
關于協程的操作作為基礎庫的一個子庫, 被放在一個獨立表 coroutine 中。
coroutine.create (f)
創建一個主體函數為 f 的新協程。 f 必須是一個 Lua 的函數。 返回這個新協程,它是一個類型為 "thread" 的對象。
coroutine.isyieldable ()
如果正在運行的協程可以讓出,則返回真。
不在主線程中或不在一個無法讓出的 C 函數中時,當前協程是可讓出的。
coroutine.resume (co [, val1, ···])
開始或繼續協程 co 的運行。 當你第一次延續一個協程,它會從主體函數處開始運行。 val1, ... 這些值會以參數形式傳入主體函數。 如果該協程被讓出,resume 會重新啟動它; val1, ... 這些參數會作為讓出點的返回值。
如果協程運行起來沒有錯誤, resume 返回 true 加上傳給 yield 的所有值 (當協程讓出), 或是主體函數的所有返回值(當協程中止)。 如果有任何錯誤發生, resume 返回 false 加錯誤消息。
coroutine.running ()
返回當前正在運行的協程加一個布爾量。 如果當前運行的協程是主線程,其為真。
coroutine.status (co)
以字符串形式返回協程 co 的狀態: 當協程正在運行(它就是調用 status 的那個) ,返回 "running"; 如果協程調用 yield 掛起或是還沒有開始運行,返回 "suspended"; 如果協程是活動的,都并不在運行(即它正在延續其它協程),返回 "normal"; 如果協程運行完主體函數或因錯誤停止,返回 "dead"。
coroutine.wrap (f)
創建一個主體函數為 f 的新協程。 f 必須是一個 Lua 的函數。 返回一個函數, 每次調用該函數都會延續該協程。 傳給這個函數的參數都會作為 resume 的額外參數。 和 resume 返回相同的值, 只是沒有第一個布爾量。 如果發生任何錯誤,拋出這個錯誤。
coroutine.yield (···)
掛起正在調用的協程的執行。 傳遞給 yield 的參數都會轉為 resume 的額外返回值。
包管理庫提供了從 Lua 中加載模塊的基礎庫。 只有一個導出函數直接放在全局環境中: require。 所有其它的部分都導出在表 package 中。
require (modname)
加載一個模塊。 這個函數首先查找 package.loaded 表, 檢測 modname 是否被加載過。 如果被加載過,require 返回 package.loaded[modname] 中保存的值。 否則,它試著為模塊尋找 加載器 。(require 遵循 package.searchers 序列的指引來查找加載器。)
package.path
這個路徑被 require 在 Lua 加載器中做搜索時用到。
在啟動時,Lua 用環境變量 LUA_PATH_5_3 或環境變量 LUA_PATH 來初始化這個變量。
package.searchers
用于 require 控制如何加載模塊的表。
package.searchpath (name, path [, sep [, rep]])
在指定 path 中搜索指定的 name 。
其余,請看文檔。
字符串處理這個庫提供了字符串處理的通用函數。 例如字符串查找、子串、模式匹配等。 當在 Lua 中對字符串做索引時,第一個字符從 1 開始計算(而不是 C 里的 0 )。 索引可以是負數,它指從字符串末尾反向解析。 即,最后一個字符在 -1 位置處,等等。
字符串庫中的所有函數都在表 string 中。字符串庫假定采用單字節字符編碼。(這意味著不是原生支持中文。)
string.byte (s [, i [, j]])
返回字符 s[i], s[i+1], ... ,s[j] 的內部數字編碼。
string.char (···)
接收零或更多的整數。 返回和參數數量相同長度的字符串。
string.find (s, pattern [, init [, plain]])
查找第一個字符串 s 中匹配到的 pattern 。 如果找到一個匹配,find 會返回 s 中關于它起始及終點位置的索引; 否則,返回 nil。 第三個可選數字參數 init 指明從哪里開始搜索; 默認值為 1 ,同時可以是負值。 第四個可選參數 plain 為 true 時, 關閉模式匹配機制。 此時函數僅做直接的 “查找子串”的操作.
string.format (formatstring, ···)
返回不定數量參數的格式化版本, 格式化串為第一個參數(必須是一個字符串)。 格式化字符串遵循 ISO C 函數 sprintf 的規則。
string.match (s, pattern [, init])
在字符串 s 中找到第一個能用 pattern (參見 §6.4.1)匹配到的部分。 如果能找到,match 返回其中的捕獲物; 否則返回 nil 。 如果 pattern 中未指定捕獲, 返回整個 pattern 捕獲到的串。 第三個可選數字參數 init 指明從哪里開始搜索; 它默認為 1 且可以是負數。
string.gmatch (s, pattern)
返回一個迭代器函數。 每次調用這個函數都會繼續以 pattern (參見 §6.4.1) 對 s 做匹配,并返回所有捕獲到的值。 如果 pattern 中沒有指定捕獲,則每次捕獲整個 pattern。
下面這個例子會循環迭代字符串 s 中所有的單詞, 并逐行打印:
s = "hello world from Lua" for w in string.gmatch(s, "%a+") do print(w) end
下一個例子從指定的字符串中收集所有的鍵值對 key=value 置入一張表:
t = {} s = "from=world, to=Lua" for k, v in string.gmatch(s, "(%w+)=(%w+)") do t[k] = v end
對這個函數來說,模板前開始的 "^" 不會當成錨點。因為這樣會阻止迭代。
string.sub (s, i [, j])
返回 s 的子串, 該子串從 i 開始到 j 為止; i 和 j 都可以為負數。
string.gsub (s, pattern, repl [, n])
將字符串 s 中,所有的(或是在 n 給出時的前 n 個) pattern (參見 §6.4.1)都替換成 repl ,并返回其副本。 repl 可以是字符串、表、或函數。 gsub 還會在第二個返回值返回一共發生了多少次匹配。 這個和python中的re.sub有點類似。
如果 repl 是一個字符串,那么把這個字符串作為替換品。 字符 % 是一個轉義符: repl 中的所有形式為 %d 的串表示 第 d 個捕獲到的子串,d 可以是 1 到 9 。 串 %0 表示整個匹配。 串 %% 表示單個 %。
如果 repl 是張表,每次匹配時都會用第一個捕獲物作為鍵去查這張表。
如果 repl 是個函數,則在每次匹配發生時都會調用這個函數。 所有捕獲到的子串依次作為參數傳入。
這里有一些用例:
x = string.gsub("hello world", "(%w+)", "%1 %1") --> x="hello hello world world" x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello world" x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") --> x="world hello Lua from" x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) --> x="home = /home/roberto, user = roberto" x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return load(s)() end) --> x="4+5 = 9" local t = {name="lua", version="5.3"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.3.tar.gz"
string.len (s)
接收一個字符串,返回其長度。 空串 "" 的長度為 0 。
string.lower (s)
接收一個字符串,將其中的大寫字符都轉為小寫后返回其副本。
string.upper (s)
string.pack (fmt, v1, v2, ···)
string.unpack (fmt, s [, pos])
返回一個打包了(即以二進制形式序列化) v1, v2 等值的二進制字符串。 字符串 fmt 為打包格式
string.rep (s, n [, sep])
返回 n 個字符串 s 以字符串 sep 為分割符連在一起的字符串。 默認的 sep 值為空字符串(即沒有分割符)。
string.reverse (s)
返回字符串 s 的翻轉串。
Lua 中的匹配模式直接用常規的字符串來描述。 它用于模式匹配函數 string.find, string.gmatch, string.gsub, string.match。
字符類:
字符類 用于表示一個字符集合。 下列組合可用于字符類:
x: (這里 x 不能是 魔法字符 ^$()%.[]*+-? 中的一員) 表示字符 x 自身。
.: (一個點)可表示任何字符。
%a: 表示任何字母。
%c: 表示任何控制字符。
%d: 表示任何數字。
%g: 表示任何除空白符外的可打印字符。
%l: 表示所有小寫字母。
%p: 表示所有標點符號。
%s: 表示所有空白字符。
%u: 表示所有大寫字母。
%w: 表示所有字母及數字。
%x: 表示所有 16 進制數字符號。
%x: (這里的 x 是任意非字母或數字的字符) 表示字符 x。 這是對魔法字符轉義的標準方法。 所有非字母或數字的字符 (包括所有標點,也包括非魔法字符) 都可以用前置一個 "%" 放在模式串中表示自身。
交叉使用類和范圍的行為未定義。 因此,像 [%a-z] 或 [a-%%] 這樣的模式串沒有意義。
所有單個字母表示的類別(%a,%c,等), 若將其字母改為大寫,均表示對應的補集。 例如,%S 表示所有非空格的字符。
如何定義字母、空格、或是其他字符組取決于當前的區域設置。 特別注意:[a-z] 未必等價于 %l 。
模式條目:
模式條目 可以是
單個字符類匹配該類別中任意單個字符;
單個字符類跟一個 "*", 將匹配零或多個該類的字符。 這個條目總是匹配盡可能長的串;
單個字符類跟一個 "+", 將匹配一或更多個該類的字符。 這個條目總是匹配盡可能長的串;
單個字符類跟一個 "-", 將匹配零或更多個該類的字符。 和 "*" 不同, 這個條目總是匹配盡可能短的串;
單個字符類跟一個 "?", 將匹配零或一個該類的字符。 只要有可能,它會匹配一個;
%n, 這里的 n 可以從 1 到 9; 這個條目匹配一個等于 n 號捕獲物(后面有描述)的子串。
%bxy, 這里的 x 和 y 是兩個明確的字符; 這個條目匹配以 x 開始 y 結束, 且其中 x 和 y 保持 平衡 的字符串。 意思是,如果從左到右讀這個字符串,對每次讀到一個 x 就 +1 ,讀到一個 y 就 -1, 最終結束處的那個 y 是第一個記數到 0 的 y。 舉個例子,條目 %b() 可以匹配到括號平衡的表達式。
%f[set], 指 邊境模式; 這個條目會匹配到一個位于 set 內某個字符之前的一個空串, 且這個位置的前一個字符不屬于 set 。 集合 set 的含義如前面所述。 匹配出的那個空串之開始和結束點的計算就看成該處有個字符 "0" 一樣。
模式:
模式 指一個模式條目的序列。 在模式最前面加上符號 "^" 將錨定從字符串的開始處做匹配。 在模式最后面加上符號 "$" 將使匹配過程錨定到字符串的結尾。 如果 "^" 和 "$" 出現在其它位置,它們均沒有特殊含義,只表示自身。
捕獲:
模式可以在內部用小括號括起一個子模式; 這些子模式被稱為 捕獲物。 當匹配成功時,由 捕獲物 匹配到的字符串中的子串被保存起來用于未來的用途。 捕獲物以它們左括號的次序來編號。 例如,對于模式 "(a(.)%w(%s))" , 字符串中匹配到 "a(.)%w(%s)" 的部分保存在第一個捕獲物中 (因此是編號 1 ); 由 "." 匹配到的字符是 2 號捕獲物, 匹配到 "%s*" 的那部分是 3 號。
作為一個特例,空的捕獲 () 將捕獲到當前字符串的位置(它是一個數字)。 例如,如果將模式 "()aa()" 作用到字符串 "flaaap" 上,將產生兩個捕獲物: 3 和 5 。
UTF-8 支持這個庫提供了對 UTF-8 編碼的基礎支持。 所有的函數都放在表 utf8 中。
utf8.char (···)
接收零或多個整數, 將每個整數轉換成對應的 UTF-8 字節序列,并返回這些序列連接到一起的字符串。
utf8.charpattern
用于精確匹配到一個 UTF-8 字節序列的模式(是一個字符串,并非函數)"0-x7FxC2-xF4*"
utf8.len (s [, i [, j]])
返回字符串 s 中 從位置 i 到 j 間 (包括兩端) UTF-8 字符的個數。 默認的 i 為 1 ,默認的 j 為 -1 。
utf8.offset (s, n [, i])
返回編碼在 s 中的第 n 個字符的開始位置(按字節數) (從位置 i 處開始統計)。
其余看文檔
表處理這個庫提供了表處理的通用函數。 所有函數都放在表 table 中。
table.concat (list [, sep [, i [, j]]])
返回字符串 list[i]..sep..list[i+1] ··· sep..list[j]。 sep 的默認值是空串, i 的默認值是 1 , j 的默認值是 #list 。 如果 i 比 j 大,返回空串。
table.insert (list, [pos,] value)
在 list 的位置 pos 處插入元素 value , 并后移元素 list[pos], list[pos+1], ···, list[#list] 。 pos 的默認值為 #list+1 , 因此調用 table.insert(t,x) 會將 x 插在列表 t 的末尾。
table.remove (list [, pos])
移除 list 中 pos 位置上的元素,并返回這個被移除的值。
table.sort (list [, comp])
在表內從 list[1] 到 list[#list] 原地 對其間元素按指定次序排序。 如果提供了 comp , 它必須是一個可以接收兩個列表內元素為參數的函數。 當第一個元素需要排在第二個元素之前時,返回真 (因此 not comp(list[i+1],list[i]) 在排序結束后將為真)。
table.pack (···)
返回用所有參數以鍵 1,2, 等填充的新表, 并將 "n" 這個域設為參數的總數。 注意這張返回的表不一定是一個序列。
table.unpack (list [, i [, j]])
返回列表中的元素。 這個函數等價于
return list[i], list[i+1], ···, list[j]
i 默認為 1 ,j 默認為 #list。
這個庫提供了基本的數學函數。 所以函數都放在表 math 中。
略。。。
I/O 庫提供了兩套不同風格的文件處理接口。 第一種風格使用隱式的文件句柄; 它提供設置默認輸入文件及默認輸出文件的操作, 所有的輸入輸出操作都針對這些默認文件。 第二種風格使用顯式的文件句柄。
當使用隱式文件句柄時, 所有的操作都由表 io 提供。 若使用顯式文件句柄, io.open 會返回一個文件句柄,且所有的操作都由該文件句柄的方法來提供。
表 io 中也提供了三個 和 C 中含義相同的預定義文件句柄: io.stdin, io.stdout, 以及 io.stderr。 I/O 庫永遠不會關閉這些文件。
I/O 函數在出錯時都返回 nil (第二個返回值為錯誤消息,第三個返回值為系統相關的錯誤碼)。 成功時返回與 nil 不同的值。
隱式文件句柄操作
io.close ([file])
等價于 file:close()。 不給出 file 時將關閉默認輸出文件。
io.flush ()
io.lines ([filename ···])
以讀模式打開指定的文件名并返回一個迭代函數。 此迭代函數的工作方式和用一個已打開的文件去調用 file:lines(···) 得到的迭代器相同。 當迭代函數檢測到文件結束, 它不返回值(讓循環結束)并自動關閉文件。
調用 io.lines() (不傳文件名) 等價于 io.input():lines("*l"); 即,它將按行迭代標準輸入文件。 在此情況下,循環結束后它不會關閉文件。
io.open (filename [, mode])
這個函數用字符串 mode 指定的模式打開一個文件。 返回新的文件句柄。 當出錯時,返回 nil 加錯誤消息。
mode 字符串可以是下列任意值:
"r": 讀模式(默認);
"w": 寫模式;
"a": 追加模式;
"r+": 更新模式,所有之前的數據都保留;
"w+": 更新模式,所有之前的數據都刪除;
"a+": 追加更新模式,所有之前的數據都保留,只允許在文件尾部做寫入。
mode 字符串可以在最后加一個 "b" , 這會在某些系統上以二進制方式打開文件。
io.popen (prog [, mode])
這個函數和系統有關,不是所有的平臺都提供。
用一個分離進程開啟程序 prog, 返回的文件句柄可用于從這個程序中讀取數據 (如果 mode 為 "r",這是默認值) 或是向這個程序寫入輸入(當 mode 為 "w" 時)。
io.input ([file])
用文件名調用它時,(以文本模式)來打開該名字的文件, 并將文件句柄設為默認輸入文件。 如果用文件句柄去調用它, 就簡單的將該句柄設為默認輸入文件。 如果調用時不傳參數,它返回當前的默認輸入文件。
io.read (···)
等價于 io.input():read(···)。
io.tmpfile ()
返回一個臨時文件的句柄。 這個文件以更新模式打開,在程序結束時會自動刪除。
io.type (obj)
檢查 obj 是否是合法的文件句柄。 如果 obj 它是一個打開的文件句柄,返回字符串 "file"。 如果 obj 是一個關閉的文件句柄,返回字符串 "closed file"。 如果 obj 不是文件句柄,返回 nil 。
io.output ([file])
類似于 io.input。 不過都針對默認輸出文件操作。
io.write (···)
等價于 io.output():write(···)。
顯式文件句柄操作
若使用顯式文件句柄, io.open 會返回一個文件句柄
file:close ()
關閉 file。
file:flush ()
將寫入的數據保存到 file 中。
file:lines (···)
返回一個迭代器函數, 每次調用迭代器時,都從文件中按指定格式讀數據。 如果沒有指定格式,使用默認值 "l" 。 看一個例子
for c in file:lines(1) do body end
會從文件當前位置開始,中不斷讀出字符。 和 io.lines 不同, 這個函數在循環結束后不會關閉文件。
file:read (···)
讀文件 file, 指定的格式決定了要讀什么。 對于每種格式,函數返回讀出的字符對應的字符串或數字。 若不能以該格式對應讀出數據則返回 nil。 (對于最后這種情況, 函數不會讀出后續的格式。) 當調用時不傳格式,它會使用默認格式讀下一行(見下面描述)。
提供的格式有
"n": 讀取一個數字,根據 Lua 的轉換文法,可能返回浮點數或整數。 (數字可以有前置或后置的空格,以及符號。) 只要能構成合法的數字,這個格式總是去讀盡量長的串; 如果讀出來的前綴無法構成合法的數字 (比如空串,"0x" 或 "3.4e-"), 就中止函數運行,返回 nil。
"i": 讀取一個整數,返回整數值。
"a": 從當前位置開始讀取整個文件。 如果已在文件末尾,返回空串。
"l": 讀取一行并忽略行結束標記。 當在文件末尾時,返回 nil 這是默認格式。
"L": 讀取一行并保留行結束標記(如果有的話), 當在文件末尾時,返回 nil。
number: 讀取一個不超過這個數量字節數的字符串。 當在文件末尾時,返回 nil。 如果 number 為零, 它什么也不讀,返回一個空串。 當在文件末尾時,返回 nil。
格式 "l" 和 "L" 只能用于文本文件。
file:seek ([whence [, offset]])
設置及獲取基于文件開頭處計算出的位置。 設置的位置由 offset 和 whence 字符串 whence 指定的基點決定。基點可以是:
"set": 基點為 0 (文件開頭);
"cur": 基點為當前位置了;
"end": 基點為文件尾;
當 seek 成功時,返回最終從文件開頭計算起的文件的位置。 當 seek 失敗時,返回 nil 加上一個錯誤描述字符串。
whence 的默認值是 "cur", offset 默認為 0 。 因此,調用 file:seek() 可以返回文件當前位置,并不改變它; 調用 file:seek("set") 將位置設為文件開頭(并返回 0); 調用 file:seek("end") 將位置設到文件末尾,并返回文件大小。
file:setvbuf (mode [, size])
設置輸出文件的緩沖模式。 有三種模式:
"no": 不緩沖;輸出操作立刻生效。
"full": 完全緩沖;只有在緩存滿或當你顯式的對文件調用 flush(參見 io.flush) 時才真正做輸出操作。
"line": 行緩沖; 輸出將到每次換行前, 對于某些特殊文件(例如終端設備)緩沖到任何輸入前。
對于后兩種情況,size 以字節數為單位 指定緩沖區大小。 默認會有一個恰當的大小。
file:write (···)
將參數的值逐個寫入 file。 參數必須是字符串或數字。
成功時,函數返回 file。 否則返回 nil 加錯誤描述字符串。
這個庫都通過表 os 實現。
os.clock ()
返回程序使用的按秒計 CPU 時間的近似值。
os.date ([format [, time]])
返回一個包含日期及時刻的字符串或表。 格式化方法取決于所給字符串 format。
如果提供了 time 參數, 格式化這個時間 (這個值的含義參見 os.time 函數)。 否則,date 格式化當前時間。
如果 format 以 "!" 打頭, 日期以協調世界時格式化。 在這個可選字符項之后, 如果 format 為字符串 "*t", date 返回有后續域的表: year (四位數字),month (1–12),day (1–31), hour (0–23),min (0–59),sec (0–61), wday (星期幾,星期天為 1 ), yday (當年的第幾天), 以及 isdst (夏令時標記,一個布爾量)。 對于最后一個域,如果該信息不提供的話就不存在。
如果 format 并非 "*t", date 以字符串形式返回, 格式化方法遵循 ISO C 函數 strftime 的規則。
os.difftime (t2, t1)
返回以秒計算的時刻 t1 到 t2 的差值。 (這里的時刻是由 os.time 返回的值)。
os.execute ([command])
它調用系統解釋器執行 command。 如果命令成功運行完畢,第一個返回值就是 true, 否則是 nil。 在第一個返回值之后,函數返回一個字符串加一個數字。如下:
"exit": 命令正常結束; 接下來的數字是命令的退出狀態碼。
"signal": 命令被信號打斷; 接下來的數字是打斷該命令的信號。
os.exit ([code [, close]])
調用 ISO C 函數 exit 終止宿主程序。 如果 code 為 true, 返回的狀態碼是 EXIT_SUCCESS; 如果 code 為 false, 返回的狀態碼是 EXIT_FAILURE; 如果 code 是一個數字, 返回的狀態碼就是這個數字。 code 的默認值為 true。
os.getenv (varname)
返回進程環境變量 varname 的值, 如果該變量未定義,返回 nil 。
os.remove (filename)
刪除指定名字的文件(在 POSIX 系統上可以是一個空目錄) 如果函數失敗,返回 nil 加一個錯誤描述串及出錯碼。
os.rename (oldname, newname)
將名字為 oldname 的文件或目錄更名為 newname。 如果函數失敗,返回 nil 加一個錯誤描述串及出錯碼。
os.time ([table])
當不傳參數時,返回當前時刻。 如果傳入一張表,就返回由這張表表示的時刻。 這張表必須包含域 year,month,及 day; 可以包含有 hour (默認為 12 ), min (默認為 0), sec (默認為 0),以及 isdst (默認為 nil)。
這個庫里的所有函數都提供在表 debug 內。 所有操作線程的函數,可選的第一個參數都是針對的線程。 默認值永遠是當前線程。
debug.traceback ([thread,] [message [, level]])
如果 message 有,且不是字符串或 nil, 函數不做任何處理直接返回 message。 否則,它返回調用棧的棧回溯信息。 字符串可選項 message 被添加在棧回溯信息的開頭。 數字可選項 level 指明從棧的哪一層開始回溯 (默認為 1 ,即調用 traceback 的那里)。
其他,請看文檔
雖然 Lua 被設計成一門擴展式語言,用于嵌入一個宿主程序。 但經常也會被當成獨立語言使用。 獨立版的 Lua 語言解釋器隨標準包發布,就叫 lua。 其命令行用法為:
lua [options] [script [args]]
選項有:
-e stat: 執行一段字符串 stat ; -l mod: “請求模塊” mod ; -i: 在運行完 腳本 后進入交互模式; -v: 打印版本信息; -E: 忽略環境變量; --: 中止對后面選項的處理; -: 把 stdin 當作一個文件運行,并中止對后面選項的處理。
在處理完選項后,lua 運行指定的 腳本。 如果不帶參數調用, 在標準輸入(stdin)是終端時,lua 的行為和 lua -v -i 相同。 否則相當于 lua - 。
為了讓 Lua 可以用于 Unix 系統的腳本解釋器。
!/usr/local/bin/lua如果 lua 在你的 PATH 中, 寫成 #!/usr/bin/env lua更為通用。
與之前版本(5.2)不兼容的地方該版本主要實現了對整數、位操作、UTF-8 的支持以及打包和解包的功能。
Lua 5.2 到 Lua 5.3 最大的變化是引入了數字的整數子類型,你可以通過把數字都強制轉換為浮點數來消除差異 (在 Lua 5.2 中,所有的數字都是浮點數)。
bit32 庫廢棄了。 使用一個外部兼容庫很容易, 不過最好直接用對應的位操作符來替換它。 (注意 bit32 只能針對 32 位整數運算, 而標準 Lua 中的位操作可以用于 64 位整數。)
io.read 的選項名不再用 "*" 打頭。 但出于兼容性考慮,Lua 會繼續忽略掉這個字符。
數學庫中的這些函數廢棄了: atan2, cosh, sinh, tanh, pow, frexp, 以及 ldexp 。 你可以用 x^y 替換 math.pow(x,y);
require 在搜索 C 加載器時處理版本號的方式有所變化。 現在,版本號應該跟在模塊名后(其它大多數工具都是這樣干的)。 出于兼容性考慮,如果使用新格式找不到加載器的話,搜索器依然會嘗試舊格式。
可以參考:http://blog.codingnow.com/201...
http://blog.csdn.net/weiyuefe...
5.1 與 5.2 是完全不兼容的,相關的第三方庫必須重新為 5.2 適配。
luajit不支持5.2,5.3
具體見
http://www.lua.org/manual/5.2...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/39421.html
摘要:多返回值開始變得越來越與眾不同了允許函數返回多個結果。這種情況函數沒有足夠的返回值時也會用來補充。中的索引習慣以開始。 showImg(https://segmentfault.com/img/bVIcQU?w=136&h=103); 為什么值得入手? Nginx作為現在使用最廣泛的高性能后端服務器,Openresty為之提供了動態預言的靈活,當性能與靈活走在了一起,無疑對于被之前陷于...
閱讀 2737·2021-10-09 09:44
閱讀 3550·2019-08-30 15:54
閱讀 2160·2019-08-30 14:16
閱讀 2790·2019-08-30 13:09
閱讀 825·2019-08-30 13:08
閱讀 1280·2019-08-29 16:29
閱讀 1662·2019-08-26 13:57
閱讀 1925·2019-08-26 13:53