Program in Lua

第一篇 語言

第0章 序言

Lua僅讓你用少量的代碼解決關(guān)鍵問題。

Lua所提供的機(jī)制是C不擅長的:高級(jí)語言,動(dòng)態(tài)結(jié)構(gòu),簡(jiǎn)潔,易于測(cè)試和調(diào)試等。

Lua的獨(dú)有特征:

(1)可擴(kuò)展性

(2)簡(jiǎn)單

(3)高效率

(4)與平臺(tái)無關(guān)

第1章 起點(diǎn)

1.1 Chunks

Lua執(zhí)行的每一塊語句,比如一個(gè)文件或者交互模式下的每一行都是一個(gè)Chunk

交互模式下 ?可調(diào)用os.exit()退出

另一個(gè)連接外部chunk的方式是使用dofile函數(shù),dofile函數(shù)加載文件并執(zhí)行它

loadfile(): 只編譯,不運(yùn)行。

dofile(): 執(zhí)行。

require(): 只執(zhí)行一次,會(huì)保存已經(jīng)加載的文件。

當(dāng)且僅當(dāng)一個(gè)變量不等于nil時(shí),這個(gè)變量存在。

在運(yùn)行參數(shù)之前,Lua會(huì)查找環(huán)境變量LUA_INIT的值,若存在且值為@filename,Lua將加載指定文件,若不以@開頭,假定為Lua代碼并執(zhí)行它。

第2章 類型和值

Lua認(rèn)為0和空串都是真

盡管字符串和數(shù)字可以自動(dòng)轉(zhuǎn)換,但兩者不同,10 == “10”是錯(cuò)的。

tonumber()將string轉(zhuǎn)成數(shù)字

tostring()將number轉(zhuǎn)成字符串

函數(shù)是第一類值(和其他變量相同)

標(biāo)準(zhǔn)庫包括:string庫,math庫,debug庫,os庫,table庫,io庫

第3章 表達(dá)式

第6章 再論函數(shù)

6.3 正確的尾調(diào)用 Proper tail calls

Lua可以正確地處理尾調(diào)用。

尾調(diào)用:當(dāng)函數(shù)最后一個(gè)動(dòng)作是調(diào)用另外一個(gè)函數(shù)時(shí),稱這種調(diào)用為尾調(diào)用。

可以在尾部以較低代價(jià)進(jìn)行遞歸。

第7章 迭代器與泛型for

7.1 迭代器與閉包

Lua中使用函數(shù)來描述迭代器,每次調(diào)用該函數(shù)就返回集合的下一個(gè)元素。閉包機(jī)制可以很容易實(shí)現(xiàn)該任務(wù)。

8. 編譯,運(yùn)行,調(diào)試

dofile

loadfile:編譯代碼為中間碼并且返回編譯后的chunk作為一個(gè)函數(shù),而不執(zhí)行代碼

loadfile返回nil和錯(cuò)誤信息,使用起來較dofile更自由

loadstring與loadfile相似

都不拋出錯(cuò)誤,只會(huì)返回nil加上錯(cuò)誤信息

Lua中的函數(shù)定義發(fā)生在運(yùn)行時(shí)的賦值而不是發(fā)生在編譯時(shí)。

loadstring(s)()//快速運(yùn)行

loadstring不關(guān)心詞法范圍,總是在全局環(huán)境中編譯他的串

8.1 require函數(shù)

require與dofile完成同樣的功能但有兩點(diǎn)不同

(1)require會(huì)搜索目錄加載文件

(2)require會(huì)判斷是否文件已經(jīng)加載避免重復(fù)加載同一文件。

require的路徑是一個(gè)模式列表

require關(guān)注的問題只有分號(hào)(模式之間的分隔符)和問號(hào)

Lua首先檢查全局變量LUA_PATH是否為一個(gè)字符串,若是,則此串為路徑,否則require使用固定的路徑

8.2 C Packages

Lua在一個(gè)叫l(wèi)oadlib的函數(shù)內(nèi)提供了所有的動(dòng)態(tài)鏈接的功能

用法:

local path = "/usr/local/lua/lib/libXXX.so"

local f = assert(loadlib(path, "luaopen_socket"))

loadlib函數(shù)加載指定的庫并連接到Lua,然而并不打開庫(也就是說沒有調(diào)用初始化函數(shù))

8.3 錯(cuò)誤

Lua中調(diào)用error("invalid input")拋出錯(cuò)誤

n = assert (io.read("*number"), "invalid input")也可拋出錯(cuò)誤

當(dāng)函數(shù)遇到異常有兩個(gè)基本的動(dòng)作,返回錯(cuò)誤代碼或者拋出錯(cuò)誤

file = assert(io.open("no-file", "r"))

io.open返回的第二個(gè)結(jié)果(錯(cuò)誤信息)作為assert的第二個(gè)參數(shù)

8.4 異常和錯(cuò)誤處理

如果在Lua中需要處理錯(cuò)誤,需要使用pcall函數(shù)封裝你的代碼

if pcall(foo) then

-- no errors while running 'foo'

else

-- foo raised an error

end

8.5 錯(cuò)誤信息和回跟蹤(tracebacks)

當(dāng)pcall返回錯(cuò)誤信息的時(shí)候他已經(jīng)釋放了保存錯(cuò)誤發(fā)生情況的棧的信息。如果想得到traceback,必須在pcall返回以前獲取。xpcall接受兩個(gè)參數(shù),調(diào)用函數(shù)和錯(cuò)誤處理函數(shù),當(dāng)錯(cuò)誤發(fā)生時(shí),Lua會(huì)在棧釋放以前調(diào)用錯(cuò)誤處理函數(shù),因此可以使用debug庫收集錯(cuò)誤相關(guān)的信息。

常用的debug處理函數(shù)debug與debug.traceback,前者給出Lua的提示符,可以動(dòng)手查看錯(cuò)誤發(fā)生時(shí)的情況,后者通過traceback創(chuàng)建更多的錯(cuò)誤信息,后者是控制臺(tái)解釋器用來構(gòu)建錯(cuò)誤信息的函數(shù)

print(debug.traceback) ?-- ?隨時(shí)查看當(dāng)前運(yùn)行的traceback信息

第9章 協(xié)同程序

9.1

9.2 管道與過濾器

協(xié)同是一種非搶占式的多線程。

協(xié)同模式下,任務(wù)間的切換代價(jià)較小,與函數(shù)調(diào)用相當(dāng),因此讀寫可以很好的協(xié)同處理

9.3 用作迭代器的協(xié)同

9.4 非搶占式多線程

不需要同步機(jī)制

第10章 完整示例

10.1 Lua作為數(shù)據(jù)描述語言使用

entry{a='a', b ='b'}

第12章 數(shù)據(jù)文件與持久化

實(shí)現(xiàn)一個(gè)健壯的讀取數(shù)據(jù)文件的程序是很困難的

數(shù)據(jù)描述是Lua的主要應(yīng)用之一

12.1 序列化

第13章 Metatables and Metamethods

(在lua代碼中的普通表,不能作為userdata的metatable。必須使用luaL_newmetatable創(chuàng)建的表才能作為userdata的metatable。)

Lua默認(rèn)創(chuàng)建一個(gè)不帶metatable的新表

t= {}

print(getmetatable(t)) -- print nil

t1 = {}

setmetatable(t, t1)

assert(getmetatable(t) == t1)

任何一個(gè)表都可以是其他一個(gè)表的metatable,一組相關(guān)的表可以共享一個(gè)metatable(描述他們共同的行為)。一個(gè)表也可以是自身的metatable(描述其私有行為)

13.1 算術(shù)運(yùn)算的Metamethods

13.4 表相關(guān)的Metamethods

13.4.1 the __index Metamethod

當(dāng)訪問一個(gè)表中不存在的域,會(huì)觸發(fā)lua解釋器去查找__index Metamethod,如果不存在,返回nil,如果存在則由__index metamethod 返回結(jié)果

__index也可以是一個(gè)表,若是函數(shù),Lua將table和缺少的域作為參數(shù)調(diào)用這個(gè)函數(shù)

一個(gè)函數(shù)的代價(jià)雖然稍微高點(diǎn),但提供了更多的靈活性:可以實(shí)現(xiàn)多繼承,隱藏,和其他一些變異的機(jī)制。

13.4.2 the __newindex Metamethod

用于對(duì)表更新,__index則用來對(duì)表訪問。當(dāng)給表的一個(gè)缺少的域賦值,解釋器就會(huì)查找__newindex metamethod:如果存在則調(diào)用這個(gè)函數(shù)而不進(jìn)行賦值操作。如果metamethod是一個(gè)表,解釋器對(duì)指定的那個(gè)表,而不是原始的表進(jìn)行賦值操作。

還有一個(gè)raw函數(shù)可以繞過Metamethod: 如調(diào)用rawset(t,k,v)不調(diào)用任何Metamethod對(duì)表t的k域賦值為v。

13.4.3 有默認(rèn)值的表

在一個(gè)普通的表中任何域的默認(rèn)值都是nil,很容易通過metatables來改變默認(rèn)值

訪問情況的唯一方法就是保持表為空。如果我們想監(jiān)控一個(gè)表的所有訪問情況,我們應(yīng)該為真實(shí)的表創(chuàng)建一個(gè)代理。

該設(shè)計(jì)不允許遍歷表

如果想監(jiān)控多張表,

13.4.4 監(jiān)控表

捕獲對(duì)一個(gè)表的所有

13.4.5 只讀表

采用代理的思想很容易實(shí)現(xiàn)一個(gè)只讀表,需要做的只是當(dāng)我們監(jiān)控到企圖修改表時(shí)拋出錯(cuò)誤。

第14章 環(huán)境

Lua將環(huán)境本身存儲(chǔ)在一個(gè)全局變量_G中,_G._G等于_G

14.1 使用動(dòng)態(tài)名字訪問全局變量

元編程meta-programming

value = _G[varname]

14.2 聲明全局變量

14.3 非全局的環(huán)境

可以使用setfenv函數(shù)來改變一個(gè)函數(shù)的環(huán)境,該函數(shù)接受函數(shù)和新的環(huán)境作為參數(shù)。除了使用函數(shù)本身,還可以指定一個(gè)數(shù)字表示棧頂?shù)幕顒?dòng)函數(shù),數(shù)字1表示當(dāng)前函數(shù),數(shù)字2代表調(diào)用當(dāng)前函數(shù)的函數(shù)

第15章 Packages

Lua并沒有提供明確的機(jī)制來實(shí)現(xiàn)packages,主要思想是:像標(biāo)準(zhǔn)庫一樣,使用表來描述package。

15.1 基本方法

都加在package表中

這種使用表來實(shí)現(xiàn)的包和真正的包的功能并不完全相同。

首先,我們對(duì)每一個(gè)函數(shù)定義都必須顯式地在前面加上包的名稱。第二,同一包內(nèi)的函數(shù)相互調(diào)用必須在被調(diào)用的函數(shù)前指定包名。

改進(jìn)方法:

可以使用固定的局部變量名,然后將這個(gè)局部變量賦值給最終的包。

這樣至少可以不再依賴于固定的包名。

15.2 私有成員

缺點(diǎn):當(dāng)修改函數(shù)的狀態(tài),必須修改函數(shù)的調(diào)用方式

解決方案:可以將package內(nèi)的所有函數(shù)都聲明為局部的,最后將他們放在最終的表中。

15.3 包與文件

15.4 使用全局表

15.5 其他一些技巧

第16章 面向?qū)ο蟪绦蛟O(shè)計(jì)

16.1 類

如果有a和b兩個(gè)對(duì)象,想讓b作為a的prototype只需要

setmetatable(a, {__index = b})

function Account:new (o)

o = o or {}

setmetatable(o, self)

self.__index = self

return o

end

getmetatable(a).__index.deposit(a, 100)

Account.deposit(a, 100)

16.2 繼承

16.3 多重繼承

實(shí)現(xiàn)關(guān)鍵:將函數(shù)用作__index,當(dāng)一個(gè)表的metatable存在一個(gè)__index函數(shù)時(shí)。如果Lua調(diào)用一個(gè)原始表中不存在的函數(shù),Lua將調(diào)用這個(gè)__index指定的函數(shù),這樣可以用__index實(shí)現(xiàn)在多個(gè)父類中查找子類不存在的域。

16.4 私有性

Lua沒有打算被用來進(jìn)行大型的程序設(shè)計(jì),其目標(biāo)定于小型到中型的程序設(shè)計(jì),通常作為大型系統(tǒng)的一部分。

Lua的另一個(gè)目標(biāo)是靈活性,提供程序員元機(jī)制(meta-mechanisms),通過他可以實(shí)現(xiàn)很多不同的機(jī)制。

設(shè)計(jì)思想為:每個(gè)對(duì)象用兩個(gè)表來表示:一個(gè)描述狀態(tài),另一個(gè)描述操作(或者叫接口),對(duì)象本身通過第二個(gè)表來訪問,也就是說,通過接口來訪問對(duì)象。為了避免未授權(quán)的訪問,表示狀態(tài)的表中不涉及到操作;表示操作的表中也不涉及到狀態(tài),取而代之的是狀態(tài)被保存在方法的閉包內(nèi),

16.5 Single-method

第20章 String庫

20.1 模式匹配函數(shù)

20.2 模式

字符類指可以匹配一個(gè)特定字符集合內(nèi)任何字符的模式項(xiàng)。

例:字符類%d匹配任意數(shù)字

模式串

字符類的補(bǔ)集

第四篇 C API

第24章 C API縱覽

C API 是一個(gè)C代碼和Lua進(jìn)行交互的函數(shù)集。由以下幾部分組成:

讀寫Lua全局變量的函數(shù)

調(diào)用Lua函數(shù)的函數(shù)

運(yùn)行Lua代碼片段的函數(shù)

注冊(cè)C函數(shù)然后可以在Lua中被調(diào)用的函數(shù)

等等

C API遵循C語言的語法形式。API中的大部分函數(shù)并不檢查他們參數(shù)的正確性。

API重點(diǎn)放在了靈活性和簡(jiǎn)潔性方面,有時(shí)候以犧牲方便實(shí)用為代價(jià)的。

在C和Lua通信關(guān)鍵內(nèi)容在于一個(gè)虛擬的棧。

棧的使用解決了C和Lua之間兩個(gè)不協(xié)調(diào)的問題。

24.1 第一個(gè)示例程序

lua.h中定義了Lua提供的基礎(chǔ)函數(shù),其中包括

創(chuàng)建一個(gè)新的Lua環(huán)境的函數(shù)如lua_open

調(diào)用Lua函數(shù)的函數(shù)如lua_pcall

讀取/寫入Lua環(huán)境的全局變量的函數(shù)。

注冊(cè)可以被Lua代碼調(diào)用的新函數(shù)的函數(shù)

等等

所有在lua.h中被定義的都有一個(gè)lua_前綴

luaxlib.h定義了輔助庫提供的函數(shù),其中所有函數(shù)都以luaL_打頭。輔助庫利用lua.h中提供的基礎(chǔ)函數(shù)提供了更高層次上的抽象;所有Lua標(biāo)準(zhǔn)庫都使用了auxlib。

24.2 堆棧

Lua和C之間交換數(shù)據(jù)時(shí)面臨兩個(gè)問題:動(dòng)態(tài)與靜態(tài)類型系統(tǒng)的不匹配和自動(dòng)與手動(dòng)內(nèi)存管理的不一致。

Lua API沒有定義任何類似lua_Value的類型,替代的方案是:用一個(gè)抽象的棧在lua與C之間交換值。棧中的每一條記錄都可以保存任何lua值

Lua以嚴(yán)格的LIFO規(guī)則來操作棧。當(dāng)調(diào)用Lua時(shí),只會(huì)改變棧頂部分。C代碼有更多自由,可以查詢棧上的任何元素,甚至在任何一個(gè)位置插入和刪除元素。

24.2.1 壓入元素

void lua_pushnil (lua_State* L)

void lua_pushboolean (lua_State* L, int bool)

void lua_pushnumber (lua_State* L, double n)

void lua_pushlstring (lua_State* L, const char* s, size_t length)//lua字符串

void lua_pushstring (lua_State* L, const char* s)//以/0結(jié)尾

Lua從來不保持一個(gè)指向外部字符串的指針,對(duì)于它保持的所有字符串,Lua要么做一份內(nèi)部的拷貝要么重新利用已經(jīng)存在的字符串。故函數(shù)返回后,可以自由修改或是釋放C中緩沖區(qū)

無論何時(shí)壓入元素到棧上,有責(zé)任確保在棧上有空間來做這件事情。

Lua調(diào)用C的時(shí)候,則至少有20個(gè)空閑的記錄。lua.h中的LUA_MINSTACK宏定義了該常量。

int lua_checkstack ( lua_State* L, int sz);

檢測(cè)棧上是否有足夠需要的空間。

24.2.2 查詢?cè)?/p>

棧中第一個(gè)元素索引為1,-1為棧頂元素

int lua_is... (lua_State* L, int index)

lua_isnumber和lua_isstring函數(shù)不檢查這個(gè)值是否是指定的類型,而是看它是否能被轉(zhuǎn)換成指定的那種類型。

為了從棧中獲得值,使用lua_to*函數(shù)

int lua_toboolean (lua_State* L, int index);

double lua_tonumber (lua_State* L, int index);

const char* lua_toString (lua_State* L, int index);

size_t lua_strlen (lua_State* L, int index);

lua_tostring函數(shù)返回一個(gè)指向字符串的內(nèi)部拷貝的指針。不能修改,只要該指針對(duì)應(yīng)的值在棧內(nèi),Lua會(huì)保證這個(gè)指針一直有效;

原則:永遠(yuǎn)不要將指向Lua字符串的指針保存到訪問他們的外部函數(shù)中。

24.2.3 其他堆棧操作

int lua_gettop (lua_State* L);//返回堆棧中元素個(gè)數(shù)。

void lua_settop(L, int index);//lua_settop(L, 0)清空堆棧

基于上面函數(shù),提供

#define lua_pop(L, n) lua_settop(L, -(n) - 1)

void lua_pushvalue (L, int index); // 壓入堆棧上指定索引的一個(gè)拷貝到棧頂

void lua_remove(L, int index);//

void lua_insert(L, int index);

void lua_replace (L, int index);

24.3 C API的錯(cuò)誤處理

Lua中所有結(jié)構(gòu)都是動(dòng)態(tài)的,按需增長,當(dāng)可能時(shí)又會(huì)縮減。因此,內(nèi)存分配失敗的可能性在Lua中是普遍的。

24.3.1 應(yīng)用程序中的錯(cuò)誤處理

運(yùn)行在非保護(hù)模式下,Lua遇錯(cuò)誤后,調(diào)用panic函數(shù)并退出應(yīng)用,可使用lua_atpanic函數(shù)設(shè)置自己的panic函數(shù)。

若不想應(yīng)用退出,必須在保護(hù)模式下運(yùn)行代碼。

所有Lua代碼使用lua_pcall()來運(yùn)行,即使錯(cuò)誤,也返回一個(gè)錯(cuò)誤代碼。

如果也想保護(hù)所有與Lua交互的C代碼,可以使用lua_cpcall

24.3.2 類庫中的錯(cuò)誤處理

C庫函數(shù)發(fā)現(xiàn)錯(cuò)誤只要簡(jiǎn)單調(diào)用lua_error,該函數(shù)會(huì)清理所有在Lua中需要被清理的,然后和錯(cuò)誤信息一起回到最初的執(zhí)行l(wèi)ua_pcall的地方。

第25章 擴(kuò)展你的程序

作為配置語言是Lua的一個(gè)重要應(yīng)用。

25.1 表操作

將key與value壓入棧中,同時(shí)table位于idx處,調(diào)用lua_settable(L, idx)

25.2 調(diào)用Lua函數(shù)

(1)將被調(diào)用的函數(shù)入棧

(2)依次將所有參數(shù)入棧

(3)使用lua_pcall調(diào)用函數(shù)

(4)從棧中獲取函數(shù)執(zhí)行返回的結(jié)果

lua_pcall()

25.3 通用的函數(shù)調(diào)用

使用C的vararg來封裝對(duì)Lua函數(shù)的調(diào)用,

第26章 調(diào)用C函數(shù)

擴(kuò)展Lua的基本方法之一:為應(yīng)用程序注冊(cè)新的C函數(shù)到Lua中去

Lua調(diào)用C函數(shù)時(shí),用來交互的棧不是全局變量,每一個(gè)函數(shù)都有他自己的私有棧。當(dāng)Lua調(diào)用C函數(shù)時(shí),第一個(gè)參數(shù)總是在這個(gè)私有棧的index=1的位置。

26.1 C函數(shù)

在Lua中注冊(cè)的函數(shù)必須符合原型

typedef int (*lua_CFunction) (lua_State* L);

返回一個(gè)表示返回值個(gè)數(shù)的數(shù)字

函數(shù)在將返回值入棧之前不需要清理?xiàng)?,函?shù)返回之后,Lua自動(dòng)的清除棧中返回結(jié)果下面的所有內(nèi)容。

lua_pushcfunction():獲取指向C函數(shù)的指針,并在Lua中創(chuàng)建一個(gè)function類型的值來表示這個(gè)函數(shù)。

lua_pushcfunction(l, l_sin);

lua_setglobal(l, "mysin");

26.2 C 函數(shù)庫

通常C庫都有一個(gè)外部的用來打開庫的函數(shù)。

luaL_openlib函數(shù)接受一個(gè)C函數(shù)的列表和他們對(duì)應(yīng)的函數(shù)名,并且作為一個(gè)庫在一個(gè)table中注冊(cè)所有這些函數(shù)。

(1)定義庫函數(shù)

(2)聲明一個(gè)luaL_reg數(shù)組,保存所有的函數(shù)和他們對(duì)應(yīng)的名字,且以{NULL,NULL}結(jié)尾

(3)使用luaL_openlib聲明主函數(shù)

luaL_openlib(L, "mylib", mylib, 0)

還可以為庫中所有函數(shù)注冊(cè)公共的upvalues。不需要時(shí),最后一個(gè)參數(shù)為0.

luaL_openlib返回的時(shí)候,將保存庫的表放到棧內(nèi)。

完成庫的代碼編寫之后,必須將它鏈接到Lua解釋器。最常用的方式是使用動(dòng)態(tài)鏈接庫。

可在lua中直接使用loadlib加載你剛才定義的函數(shù)庫。

mylib = loadlib("fullname-of-your-library", "luaopen_mylib")

然后定義mylib(),將運(yùn)行l(wèi)uaopen_mylib()打開定義的函數(shù)庫。

當(dāng)打開一個(gè)新的狀態(tài)時(shí),必須打開這個(gè)新定義的函數(shù)庫。

當(dāng)解釋器創(chuàng)建新的狀態(tài)的時(shí)候會(huì)調(diào)用這個(gè)宏

#define LUA_EXTRALIBS {"mylib", XXXXX}

第27章 撰寫C函數(shù)的技巧

27.1 數(shù)組操作

lua_settable ? ? ? ? ? ? ?lua_gettable

出于性能考慮的數(shù)組操作

void lua_rawgeti (lua_State * L, int index, int key)

void lua_rawseti (lua_State * L, int index, int key)

27.2 字符串處理

當(dāng)C函數(shù)接受一個(gè)來自lua的字符串作為參數(shù)時(shí),有兩個(gè)規(guī)則必須遵守:當(dāng)字符串正在被訪問的時(shí)候不要將其出棧,永遠(yuǎn)不要修改字符串。

27.3 在C函數(shù)中保存狀態(tài)

用于C語言保留一些非局部的數(shù)據(jù)

Lua提供了一個(gè)獨(dú)立地被稱為registry的表,C代碼可以自由使用,但Lua代碼不能訪問。

27.3.1 the registry

registry位于一個(gè)由LUA_REGISTRYINDEX定義的值所對(duì)應(yīng)的假索引的位置。一個(gè)假索引除了他對(duì)應(yīng)的值不在棧中之外,其他都類似于棧中的索引。

第28章 User-defined Types in C

使用C函數(shù)來擴(kuò)展Lua功能。

如何使用C中新類型來擴(kuò)展Lua。

28.1 Userdata

void * lua_newuserdata (lua_State* L, size_t size);

按照指定大小分配一塊內(nèi)存,將對(duì)應(yīng)的userdatum放到棧內(nèi),并返回內(nèi)存塊的地址。

luaL_checkint()

luaL_argcheck()

28.2 Metatables

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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