欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:Lua 進階 · 教程筆記

柚子快報邀請碼778899分享:Lua 進階 · 教程筆記

http://yzkb.51969.com/

Lua 進階 · 教程筆記

前言1. 概述(略)2. 查看官方接口文檔3. require 多文件調(diào)用4. 迭代 table5. string6. 正則7. 元表,面向?qū)ο笤砗驮椒嫦驅(qū)ο?/p>

8. 協(xié)程 coroutine9. 二進制數(shù)據(jù)打包與解析字節(jié)序——大端和小端Lua 處理包的二進制數(shù)據(jù)

前言

筆記的內(nèi)容出自 Bilibili 上的視頻:Lua教程-進階部分 - 4K超清【不定期更新】

筆記主要用于供筆者個人或讀者回顧知識點,如有紕漏,煩請指出 : )

1. 概述(略)

2. 查看官方接口文檔

國內(nèi)的大佬 云風(fēng) 翻譯了 Lua 的 Api 參考手冊:傳送門【】

以后讀者在練習(xí)或者開發(fā)途中可以在參考手冊里查看 Lua 提供的 Api。

3. require 多文件調(diào)用

Lua 提供了一個 require() 方法可以運行指定 Lua 文件,示例如下:

hello.lua

print("Hello Lua!")

test.lua

require("hello") -- 運行 test.lua 后,輸出 Hello Lua!

可見,require() 方法不需要 Lua 文件的后綴 “.lua”。

如果是在不同路徑下,我們需要提供其完整的路徑。

在同目錄下創(chuàng)建一個名叫 Fold 的文件夾,里面新建一個名為 hello2 的 lua 文件,如下:

hello2.lua

print("Hello Lua!2")

目錄層級用 . 分隔,實際上用 / 也能正常運行。

test.lua

require("Fold.hello2") -- 運行 test.lua 后,輸出 Hello Lua!2

require() 方法只會運行一次。

下面做一個測試,在 test.lua 里聲明一個全局的計數(shù)變量 count;在 hello.lua 里給這個全局變量加 1,然后在 test.lua 里多次調(diào)用 require() 方法,最后查看 count 的值是多少。

hello.lua

_G.count = _G.count + 1

test.lua

_G.count = 1 -- 初始值為 1

require("hello")

require("hello")

require("hello")

print(count) -- 運行 test.lua 后,輸出為 2

require 會從 package.path 中的路徑里查找。

package.path 其實就是 Lua 的默認搜索路徑,讀者可以將其輸出看看相應(yīng)格式。往搜索路徑里加入目標路徑可以在使用 require() 方法的時候省略對應(yīng)路徑。

test.lua

package.path = package.path..";./Fold/?.lua"

require("hello2") -- 可正確運行

一般 require() 只是用來引用調(diào)用的外部庫的,所以不需要多次調(diào)用。如果實在有這個需求,可以用 luaL_dofile()、load()、luaL_loadstring() 等替代。

最后來演示下 require() 的一種用途:返回表實例。

hello.lua

local hello = {}

function hello.say()

print("Hello World!")

end

return hello

test.lua

local ins = require("hello")

ins.say() -- 輸出 Hello World!

4. 迭代 table

Lua 提供了 ipairs() 來迭代數(shù)組中的元素(即所有元素都是同類型的)。

t = {"a", "b", "c", "d"}

for i,j in ipairs(t) do

print(i, j)

end

不過 ipairs() 遇到了不連續(xù)的數(shù)字下標的數(shù)組,則會失效:

t = {

[1] = "a",

[2] = "b",

[3] = "c",

[5] = "d"

}

for i,j in ipairs(t) do

print(i, j)

end

-- 不會輸出 5 d,因為檢測到下標 4 是 nil,就停止了

如果想迭代不連續(xù)的數(shù)字下標的數(shù)組,抑或是字符串為下標的數(shù)組,Lua 提供了 pairs()。

t = {

apple = "a",

banana = "b",

eraser = "c",

water = "d"

}

for i,j in pairs(t) do

print(i, j)

end

-- 正常輸出

pairs() 內(nèi)部使用了 next() 方法,它會返回其認定的下一個對象,如果下一個對象為空則返回 nil。

其有一個巧妙用法則是可以用于快速判斷表是否為空。

t = {}

print(next(t)) -- 輸出 nil

5. string

在 Lua 里,字符串是一個一個字節(jié)地存儲字符的 Ascii 碼值的,并且可以存儲任何 Byte 值(包括 0,但是 C 語言就不能存字符 0,它意味著結(jié)束)。并且下標倒序從 -1 開始。

string.byte() 可以返回目標字符的十進制數(shù)字編碼。

local s = "123"

print(string.byte(s, 1)) -- 輸出 49

print(s:byte(1)) -- 字符串庫的語法糖,方便代碼編寫,同樣輸出 49

-- 輸出字符串內(nèi)所有字符的十進制值

print(s:byte(1, -1)) -- 輸出 49 ~ 57

string.char() 可以返回數(shù)字對應(yīng)的字符。

print(string.char(0x35, 0x36, 0x37)) -- 輸出 567

local b = string.char(3, 4, 5)

print(b:byte(1, -1)) -- 輸出 3 4 5

string.format() 是 C 語言里的格式化字符串。

local f = string.format("%d心%d意", 3, 2)

print(f) -- 輸出 3心2意

string.len() 可以返回字符串的長度。# 也可以。

string.lower() 可以將字符串中的大寫字符轉(zhuǎn)換為小寫后返回其副本。

string.pack() 用于將一組數(shù)據(jù)打包成一個二進制字符串??梢杂糜诰W(wǎng)絡(luò)傳輸、文件存儲等場景。string.unpack() 可以將其解包成原來的數(shù)據(jù)。

string.rep() 就是一個用于重復(fù)目標字符串的方法。

local rep = string.rep("123", 3)

print(rep) -- 輸出 123123123

rep = string.rep("123", 3, ",") -- 第三個參數(shù)是分隔符

print(rep) -- 輸出 123,123,123

string.reverse() 就是反轉(zhuǎn)字符串。

string.sub() 用于切割字符串。

local str = "123456"

print(str:sub(3, 5)) -- 輸出 345

6. 正則

string.find() 用于搜尋字符串里的目標字符串的位置。

string.match() 可以搜尋到字符串里的目標字符串。

local s = "abcd1234abccc"

print(string.find(s, "123")) -- 輸出 5 7

print(string.match(s, "123")) -- 輸出 123

上面的代碼看起來好像顯得 string.match() 很雞肋,不過配合上正則表達式就不一樣了。

此處是一個正則表達式的測試網(wǎng)站:傳送門【】

下圖截取自 Lua 5.3 參考手冊里關(guān)于正則表達式可用的字符類:

下圖是簡單測試正則表達式配合 string.find() 和 string.match() 的效果:查找字符串中第一個先是數(shù)字后是字母的位置。

正則表達式的轉(zhuǎn)義符號是 %,比如匹配一個字符 . 可以寫成 %.使用 [ ] 可以同時運用多種匹配條件,比如下圖就是匹配 “d 后面跟字母或數(shù)字”

可以通過匹配條目來匹配多個。

( ) 用于指定匹配的部分,比如 d([%d%a]) 就是 “只要 d 后面跟的這個字母或數(shù)字”;有多對括號就返回多個匹配結(jié)果。

string.gsub() 用于替換字符串的指定位置內(nèi)容。

local s = "abcd1234abccc"

print(string.gsub(s, "%d", "x")) -- 輸出 abcdxxxxabccc 4

-- 輸出的數(shù)字 4 就是執(zhí)行替換的次數(shù)

string.gmatch() 可以迭代捕獲字符串里面的目標字符串。

s = "a1a2a3a4a5a6a7"

for w in string.gmatch(s, "a%d") do

print(w)

end

-- 輸出 a1 ~ a7

7. 元表,面向?qū)ο?/p>

元表和元方法

Lua 中的每個值都可以有一個 元表。它就是一個普通的 Lua 表,用于定義原始值在特定操作下的行為。

t = {num = 1}

mt = {

__add = function(a, b) -- 定義在參與加法運算時的表現(xiàn)行為

return a.num + b

end,

}

setmetatable(t, mt) -- 設(shè)置 mt 為 t 的元表

print(t + 1) -- 輸出 2

除 __add 表示加法行為外,還有其他的方法,詳情可查詢參考手冊。

__index 表示通過下標取值失敗時所作出的行為。

t = {num = 1}

mt = {

__index = function(table, key) -- 定義在下標取值失敗時的表現(xiàn)行為

return 555

end,

}

setmetatable(t, mt)

print(t["empty"]) -- 取一個不存在的下標,輸出 555

實際上這個事件的元方法既可以是函數(shù),也可以是一張表。

t = {num = 1}

mt = {

__index = {

empty = 0,

num1 = 100

}

}

setmetatable(t, mt)

print(t["empty"]) -- t 內(nèi)找不到 "empty",從返回的表里面找,輸出 0

print(t["num1"]) -- 輸出 100

__newindex 會在賦值時觸發(fā)。

t = {num = 1}

mt = {

__newindex = function(t, k, v)

end

}

setmetatable(t, mt)

t["fail"] = 404

print(t["fail"]) -- 輸出 nil, 因為觸發(fā)了 __newindex,而里面也沒有邏輯

可以通過 rawset() 來避免觸發(fā)元方法并賦值元素。

t = {num = 1}

mt = {

__newindex = function(t, k, v)

rawset(t, k, v)

end

}

setmetatable(t, mt)

t["fail"] = 404

print(t["fail"]) -- 賦值成功,輸出 404

面向?qū)ο?/p>

其實在《Lua 快速入門》的筆記里 v:function(args) 這個語法糖就相當于 v.function(v, args),這里的 v 只會被求值一次。

接下來配合元表來實現(xiàn)面向?qū)ο蟆?/p>

bag = {}

bagmt = {

put = function(t, item) -- put 方法

table.insert(t.items, item)

end,

take = function(t) -- take 方法

return table.remove(t.items, 1)

end,

list = function(t) -- list 方法

return table.concat(t.items, ", ")

end,

clear = function(t) -- clear 方法

t.items = {}

end

}

bagmt["__index"] = bagmt -- 讓元表的 __index 指向自身

function bag.new() -- 構(gòu)造函數(shù)

local t = {

items = {} -- 裝東西的表

}

setmetatable(t, bagmt)

return t

end

local b = bag.new() -- 實例化

b:put("apple")

print(b.items[1]) -- 輸出 apple

print(b:take()) -- 輸出 apple

b:put("apple")

b:put("apple")

b:put("apple")

print(b:list()) -- 輸出 apple, apple, apple

-- 再額外創(chuàng)建兩個實例,確認是否實例之間互相獨立

local a = bag.new()

local c = bag.new()

a:put("apple")

c:put("candy")

print(a:list()) -- 輸出 apple

print(b:list()) -- 輸出 apple, apple, apple

print(c:list()) -- 輸出 candy

8. 協(xié)程 coroutine

Lua 支持協(xié)程,也叫 協(xié)同式多線程。一個協(xié)程在 Lua 中代表了一段獨立的執(zhí)行線程(實際上 Lua 里每個協(xié)程都是單線程,只是分時復(fù)用顯得它像多線程)。不過它與多線程系統(tǒng)中的線程的區(qū)別在于,協(xié)程僅在顯式調(diào)用一個讓出 (yield) 函數(shù)時才掛起當前的執(zhí)行。

coroutine.create(f) 表示創(chuàng)建一個主體函數(shù)為 f 的新協(xié)程。它會返回一個類型為 “thread” 的對象。

coroutine.resume() 可以開始或繼續(xù)協(xié)程的運行。

local co = coroutine.create(function()

print("hello world!!")

end)

print(type(co)) -- 打印類型,輸出 thread

coroutine.resume(co) -- 輸出 hello world!!

coroutine.yield() 可以掛起正在調(diào)用的協(xié)程的執(zhí)行。

local co = coroutine.create(function()

print("hello world!!")

coroutine.yield(1, 2, 3)

print("coroutine run again")

end)

-- resume 可以接收 coroutine.yield() 返回的內(nèi)容

print("coroutine.resume", coroutine.resume(co))

-- 輸出如下

-- hello world!!

-- coroutine.resume true 1 2 3

coroutine.resume(co) -- 輸出 coroutine run again

還可以在 coroutine.resume() 里傳入?yún)?shù)到 coroutine.yield()。

local co = coroutine.create(function()

print("hello world!!")

local r1, r2, r3 = coroutine.yield(1, 2, 3)

print("coroutine run again", r1, r2, r3)

end)

print("coroutine.resume", coroutine.resume(co))

-- 輸出如下

-- hello world!!

-- coroutine.resume true 1 2 3

coroutine.resume(co, 4, 5, 6) -- 傳入 4, 5, 6

-- 輸出 coroutine run again 4 5 6

coroutine.wrap(f) 可以創(chuàng)建一個主體函數(shù)為 f 的新協(xié)程,但是它會返回一個函數(shù),每次調(diào)用該函數(shù)都會延續(xù)該協(xié)程。傳給這個函數(shù)的參數(shù)都會作為 resume() 的額外參數(shù)。和 resume() 返回相同的值,只不過沒有第一個 bool 值。

local co = coroutine.wrap(function()

print("hello world!!")

local r1, r2, r3 = coroutine.yield(1, 2, 3)

print("coroutine run again", r1, r2, r3)

end)

print("coroutine.resume", co()) -- 替換為 co

-- 輸出如下

-- hello world!!

-- coroutine.resume true 1 2 3

co(4, 5, 6)

-- 輸出 coroutine run again 4 5 6

coroutine.status(co) 會以字符串形式返回協(xié)程 co 的狀態(tài)。

running:正在運行suspended:調(diào)用 yield 掛起 或 還沒有開始運行normal:在活動,但并不在運行(即正在延續(xù)其他協(xié)程)dead:運行完主體函數(shù) 或 因錯誤停止

-- 設(shè)為全局協(xié)程函數(shù)

co = coroutine.create(function()

print("hello world!!")

local r1, r2, r3 = coroutine.yield(1, 2, 3)

print("inside", coroutine.status(co)) -- 輸出 inside running

print("coroutine run again", r1, r2, r3)

end)

print("1", coroutine.status(co)) -- 輸出 1 suspended

print("coroutine.resume", coroutine.resume(co))

coroutine.resume(co, 4, 5, 6)

print("2", coroutine.status(co)) -- 輸出 2 dead

-- 結(jié)束后繼續(xù)調(diào)用 resume()

print(coroutine.resume(co))

-- 輸出如下

-- false cannot resume dead coroutine

9. 二進制數(shù)據(jù)打包與解析

字節(jié)序——大端和小端

大端也可以稱作網(wǎng)絡(luò)序,因為 TCP 和 UDP 的包一般是按大端來排序的。硬件里面微程序控制器 MCU 一般是小端排序的。

可見,大端和小端在內(nèi)存里存儲數(shù)據(jù)的順序是相反的。

Lua 處理包的二進制數(shù)據(jù)

對于 Lua 5.3 以上版本,使用 string.pack(); 對于 Lua 5.2 及以下版本,使用 lpack 庫。其實二者差別不大。

區(qū)別在于二者的 unpack() 的參數(shù) 1 和 參數(shù) 2 位置是相反的。

string.pack() 要用到格式串,如下:

-- uint32_t n = 0x00000001

-- 小端編碼

local data = string.pack("

print("len:", #data) -- 輸出 len: 4

print(data:byte(1)) -- 輸出 1

print(data:byte(2)) -- 輸出 0

print(data:byte(3)) -- 輸出 0

print(data:byte(4)) -- 輸出 0

-- 大端編碼

local data1 = string.pack(">L", 1)

print("len:", #data) -- 輸出 len: 4

print(data1:byte(1)) -- 輸出 0

print(data1:byte(2)) -- 輸出 0

print(data1:byte(3)) -- 輸出 0

print(data1:byte(4)) -- 輸出 1

string.unpack() 使用如下:

-- 大端編碼

local data = string.pack(">L", 1)

local c = string.unpack(">L", data)

-- 如果有多個對象就相應(yīng)地增加格式串

local r1, r2 = string.unpack(">LL", data..data)

print(c) -- 輸出 1

print(r1, r2) -- 輸出 1 1

柚子快報邀請碼778899分享:Lua 進階 · 教程筆記

http://yzkb.51969.com/

精彩內(nèi)容

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18817247.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機訪問

文章目錄