中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

套網(wǎng)站模板軟件wix網(wǎng)站制作

套網(wǎng)站模板軟件,wix網(wǎng)站制作,涿鹿做網(wǎng)站wl17581,建設(shè)銀行網(wǎng)站轉(zhuǎn)賬使用RedisTemplate執(zhí)行l(wèi)ua腳本 在開發(fā)中,我們經(jīng)常需要與Redis數(shù)據(jù)庫進(jìn)行交互,而Redis是一個基于內(nèi)存的高性能鍵值存儲數(shù)據(jù)庫,它支持多種數(shù)據(jù)結(jié)構(gòu),并提供了豐富的命令接口。在某些情況下,我們可能需要執(zhí)行一些復(fù)雜的邏…

使用RedisTemplate執(zhí)行l(wèi)ua腳本

在開發(fā)中,我們經(jīng)常需要與Redis數(shù)據(jù)庫進(jìn)行交互,而Redis是一個基于內(nèi)存的高性能鍵值存儲數(shù)據(jù)庫,它支持多種數(shù)據(jù)結(jié)構(gòu),并提供了豐富的命令接口。在某些情況下,我們可能需要執(zhí)行一些復(fù)雜的邏輯操作,這時可以使用Lua腳本來實(shí)現(xiàn)這些邏輯,而Redis提供了執(zhí)行Lua腳本的功能。在Spring應(yīng)用程序中,我們可以使用RedisTemplate來執(zhí)行Lua腳本。

為什么使用Lua腳本

Redis本身提供了許多命令,可以完成各種操作,但有時候我們需要執(zhí)行一些比較復(fù)雜的邏輯操作,這時使用Lua腳本可以幫助我們在一次網(wǎng)絡(luò)往返中完成多個命令操作,減少了網(wǎng)絡(luò)開銷,提高了執(zhí)行效率。此外,Lua腳本在Redis服務(wù)器端執(zhí)行,可以減少客戶端與服務(wù)器之間的通信次數(shù),提高了性能。

結(jié)合Redis和lua腳本語言的特性,如果在Redis里遇到如下需求,就可以引入lua腳本。

  • 重復(fù)執(zhí)行相同類型的命令,比如要緩存1到1000的數(shù)字到內(nèi)存里。
  • 在高并發(fā)場景下減少網(wǎng)絡(luò)調(diào)用的開銷,一次性執(zhí)行多條命令。
  • Redis會將lua腳本作為一個整體來執(zhí)行,天然具有原子性。

使用RedisTemplate執(zhí)行Lua腳本

在Spring應(yīng)用程序中,我們可以通過RedisTemplate來執(zhí)行Lua腳本。RedisTemplate是Spring Data Redis提供的用于與Redis數(shù)據(jù)庫進(jìn)行交互的模板類,它封裝了Redis的各種操作,并提供了方便的方法來執(zhí)行Lua腳本。

以下是使用RedisTemplate執(zhí)行Lua腳本的一般步驟:

  1. 添加Spring Data Redis依賴: 首先,確保你的Spring Boot項(xiàng)目中已經(jīng)添加了Spring Data Redis依賴。你可以在項(xiàng)目的pom.xml文件中添加以下依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置RedisTemplate: 在Spring Boot項(xiàng)目的配置文件中(例如application.properties或application.yml)配置Redis連接信息和RedisTemplate。以下是一個示例配置:
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=your_redis_password

在Java代碼中,你可以配置RedisTemplate bean,如下所示:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new StringRedisSerializer()); // 根據(jù)需要設(shè)置值的序列化器template.setEnableTransactionSupport(true); // 支持事務(wù)template.afterPropertiesSet();return template;}
}
  1. 執(zhí)行Lua腳本: 現(xiàn)在,你可以在Spring Boot服務(wù)中使用RedisTemplate執(zhí)行Lua腳本。以下是一個示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;import java.util.Collections;
import java.util.List;@Service
public class LuaScriptService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public String executeLuaScript() {// Lua腳本內(nèi)容String luaScript = "return 'Hello, Lua!'";// 創(chuàng)建RedisScript對象RedisScript<String> script = new DefaultRedisScript<>(luaScript, String.class);// 執(zhí)行Lua腳本String result = redisTemplate.execute(script, Collections.emptyList());return result;}
}

在這個示例中,我們首先定義了一個Lua腳本字符串,并使用DefaultRedisScript創(chuàng)建了一個RedisScript對象。然后,我們使用RedisTemplate的execute方法執(zhí)行Lua腳本,并傳遞一個空參數(shù)列表。

這只是一個簡單的示例,你可以根據(jù)需要編寫更復(fù)雜的Lua腳本,并使用RedisTemplate來執(zhí)行它們。需要確保在執(zhí)行Lua腳本時使用正確的參數(shù)和數(shù)據(jù)類型,以便與Redis進(jìn)行正確的交互。

在這里插入圖片描述

-- 此腳本的功能是:將傳入的key增加1,并且如果是第一次操作這個key,則給其設(shè)置傳入的過期時間。
local results = {}
-- 這里的 for 循環(huán)中出現(xiàn)了兩個循環(huán)變量,分別表示索引和值;ipars 是只遍歷存在于數(shù)組里面的元素;ARGV[idx]表示取參數(shù)值
for idx,key in ipairs(KEYS) dolocal value = tonumber(ARGV[idx])local total = redis.call('INCR', key)table.insert(results, total)if total == 1 thenredis.call('EXPIRE', key, value)end
end
return results

文件讀取第一種方式

@Configuration
public class RedisScriptConfig {@Beanpublic RedisScript<List<Long>> batchIncrWithExpireScript() {Resource scriptSource = new ClassPathResource("redis-scripts/batchIncrWithExpire.lua");String script;try {script = StreamUtils.copyToString(scriptSource.getInputStream(), StandardCharsets.UTF_8);} catch (IOException e) {throw new IllegalStateException("Unable to load lua script", e);}return new DefaultRedisScript(script, List.class);}}
@Component
@Slf4j
public class RedisUtils {@Resource(name = "batchIncrWithExpireScript")private RedisScript<List<Long>> batchIncrWithExpireScript;public void batchIncrWithExpire(Map<String, String> keyValueMap) {// 準(zhǔn)備鍵和值的列表List<String> keys = new ArrayList<>(keyValueMap.keySet());List<String> values = keyValueMap.values().stream().toList();// 執(zhí)行Lua腳本List<Long> results = stringRedisTemplate.execute(batchIncrWithExpireScript, keys, values.toArray());}}

文件讀取第二種方式

要在Spring Boot項(xiàng)目中運(yùn)行一個Lua腳本文件,你可以按照以下步驟進(jìn)行操作:

  1. 創(chuàng)建Lua腳本文件: 首先,創(chuàng)建一個包含你的Lua腳本的文件(例如,myscript.lua),并將其保存在項(xiàng)目的合適位置。在這個文件中,你可以編寫你的Lua腳本代碼。
  2. 加載Lua腳本文件: 在Spring Boot服務(wù)中,你需要加載Lua腳本文件并將其內(nèi)容傳遞給RedisTemplate來執(zhí)行。你可以使用Java的文件讀取方法來加載Lua腳本文件的內(nèi)容。
  3. 執(zhí)行Lua腳本: 使用RedisTemplate執(zhí)行加載的Lua腳本內(nèi)容。你可以使用DefaultRedisScript來創(chuàng)建RedisScript對象,并在執(zhí)行時傳遞適當(dāng)?shù)膮?shù)。
    以下是示例代碼,演示如何加載并執(zhí)行Lua腳本文件:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;@Service
public class LuaScriptFileService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public String executeLuaScriptFromFile() throws IOException {// 加載Lua腳本文件Resource resource = new ClassPathResource("redis-scripts/batchIncrWithExpire.lua");String luaScript = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);// 創(chuàng)建RedisScript對象RedisScript<String> script = new DefaultRedisScript<>(luaScript, String.class);// 執(zhí)行Lua腳本String result = redisTemplate.execute(script, Collections.emptyList());return result;}
}

在這個示例中,我們首先加載Lua腳本文件的內(nèi)容并將其存儲在luaScript字符串中。然后,我們使用DefaultRedisScript創(chuàng)建了RedisScript對象,并在執(zhí)行時傳遞了一個空參數(shù)列表。你需要替換path/to/myscript.lua為你的Lua腳本文件的實(shí)際路徑。

現(xiàn)在,你可以在Spring Boot服務(wù)中調(diào)用executeLuaScriptFromFile方法來執(zhí)行Lua腳本文件中的內(nèi)容。

請確保Lua腳本文件的路徑和文件名正確,并且具有適當(dāng)?shù)脑L問權(quán)限。此外,根據(jù)需要,你可以傳遞參數(shù)給Lua腳本,并在Lua腳本中使用KEYSARGV來引用它們。

文件讀取第三種方式

你可以直接使用DefaultRedisScript來讀取Lua腳本文件,而不需要手動加載文件內(nèi)容。以下是如何使用DefaultRedisScript來執(zhí)行Lua腳本文件的示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;import java.util.Collections;
import java.util.List;@Service
public class LuaScriptFileService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public String executeLuaScriptFromFile() {Resource scriptSource = new ClassPathResource("redis-scripts/batchIncrWithExpire.lua");RedisScriptList<Long> script = RedisScript.of(scriptSource, List.class);// 執(zhí)行Lua腳本String result = redisTemplate.execute(script, Collections.emptyList());return result;}
}

在這個示例中,我們通過將Lua腳本文件的路徑傳遞給DefaultRedisScript的構(gòu)造函數(shù)來創(chuàng)建了RedisScript對象。然后,我們可以使用execute方法來執(zhí)行Lua腳本文件中的內(nèi)容。這種方法更簡潔,省去了手動加載文件內(nèi)容的步驟。

確保將"redis-scripts/batchIncrWithExpire.lua"替換為你實(shí)際的Lua腳本文件路徑。此外,根據(jù)需要,你可以傳遞參數(shù)給Lua腳本,并在Lua腳本中使用KEYSARGV來引用它們。

用一篇文章讓你學(xué)會腳本語言Lua

Lua的數(shù)據(jù)結(jié)構(gòu)、關(guān)鍵字、注釋

任何一門語言都提供了不同類型的數(shù)據(jù)結(jié)構(gòu),那么 Lua 中都有哪些數(shù)據(jù)結(jié)構(gòu)呢?

  • nil:空
  • boolean:布爾類型,分別是 true 和 false
  • number:數(shù)值型,整型和浮點(diǎn)型都屬于 number
  • string:字符串
  • table:表
  • function:函數(shù)
  • userdata:用戶數(shù)據(jù)
  • thread:線程

Lua 總共提供了以上 8 種數(shù)據(jù)類型,目前只需要知道一下即可,后面會一點(diǎn)一點(diǎn)介紹。


然后是 Lua 的關(guān)鍵字,總共有 22 個,如下所示。

and break do else elseif end false 
goto for function if in local nil 
not or repeat return then true until while

這些關(guān)鍵字顯然基本上都見過,后續(xù)會慢慢遇到。


最后是 Lua 的注釋,Lua 也分單行注釋和多行注釋,單行注釋和 SQL 一樣以 -- 開頭,多行注釋則以 --[[ 開頭、]] 結(jié)尾,里面寫注釋。

-- 這是單行注釋--[[這是多行注釋并且開頭的 -- 和 [[ 之間不可以有空格,結(jié)尾是兩個 ]]]--[[這也是多行注釋不是兩行單行注釋--]]

以上我們對 Lua 便有了一個初步認(rèn)識,下面來學(xué)習(xí) Lua 的數(shù)據(jù)結(jié)構(gòu)。

Lua 的數(shù)值

Lua 的數(shù)值類型為 number,無論是整數(shù)還是浮點(diǎn)型,類型都是 number。

-- Lua 和 Python 類似,在創(chuàng)建變量時不需要指定類型,解釋器會自動根據(jù)賦的值來判斷
a = 123
b = 3.14
print(a, b)  -- 123	3.14-- Lua中,每一行語句的結(jié)尾也不需要加分號,直接換行即可
-- 當(dāng)然加分號也可以,跟 Python 是類似的
c = 123;
d = 456
print(c, d)  -- 123	456-- 并且在 Python 中,如果加上了分號,那么兩行賦值可以寫一行
-- 比如 e = 1; f = 2,這在 Lua 中也是可以的
e = 1; f = 2
print(e, f)  -- 1	2-- 但 Lua 更加彪悍,不加分號也可以
-- 如果在 Python 中這么寫,則肯定是報(bào)錯的
g = 3 h = 4
print(g, h)  -- 3	4-- 但是我們不建議將多行賦值語句寫在同一行里面,最好要分行寫
-- 如果寫在同一行,那么應(yīng)該使用 Lua 的多元賦值
a, b = 1, 2
print(a, b)  -- 1	2

可能有人發(fā)現(xiàn)了,我們在最上面已經(jīng)創(chuàng)建 a 和 b 這兩個變量了,但是最后又創(chuàng)建了一次,這一點(diǎn)和 Python 類似,可以創(chuàng)建多個同名變量。比如創(chuàng)建 a = 1,然后又創(chuàng)建 a = 2,這是允許的,只不過相當(dāng)于發(fā)生了更新,將 a 的值由 1 變成了 2,當(dāng)然即便賦值為其它類型也沒問題。比如先創(chuàng)建 a = 數(shù)值,然后再將 a 的值換成字符串,這一點(diǎn)和 Python 一樣,因?yàn)樵?Lua 中,全局變量是通過 table、也就是"表"來存儲的。

這個 table 后面會詳細(xì)說,你暫時可以理解為哈希表,或者當(dāng)成 Python 的字典,而且 Python 中全局變量也是通過字典存儲的。

我們通過 Lua 的數(shù)值,演示了在 Lua 中如何創(chuàng)建一個變量,并且還介紹了 Lua 中全局變量的存儲方式。然后是整數(shù)和浮點(diǎn)數(shù)的區(qū)分,既然它們的類型都是 number,那要怎么區(qū)分呢?

a = 123
b = 123.  -- . 后面不寫東西的話,默認(rèn)是 .0
c = .123  -- . 前面不寫東西的話,默認(rèn)是 0.
print(a, b, c)  -- 123	123.0	0.123-- Lua 中,可以使用 type 函數(shù)檢測變量的類型
print(type(a))  -- number
print(type(b))  -- number
print(type(c))  -- number-- 這個 type 是內(nèi)置的,它檢測的是 lua 中的基礎(chǔ)類型
-- 而我們說 Lua 不區(qū)分整型和浮點(diǎn)型,如果想精確區(qū)分的話,那么可以使用 math.type
-- 整型是 integer,浮點(diǎn)型是 float
print(math.type(a))  -- integer
print(math.type(b))  -- float
print(math.type(c))  -- float
-- 如果一個數(shù)值中出現(xiàn)了小數(shù)點(diǎn),那么 math.type 得到的就是 float

使用 type 和 math.type 得到的都是一個字符串,另外我們是直接使用的 math.type,這個 math 類似于一個外部包。比如 Python 也有 math 包,只不過在 Lua 中不需要像 Python 那樣顯式導(dǎo)入,直接用即可,包括后面處理字符串用的包也是如此。

整數(shù)和浮點(diǎn)數(shù)之間的比較

整數(shù)和浮點(diǎn)數(shù)可以比較:

print(3 == 3.0)  -- true
print(-3 == -3.0)  -- true-- 我們看到,如果小數(shù)點(diǎn)后面是 0,那么是相等的,這一點(diǎn)和 Python 一樣
-- 另外 Lua 也支持科學(xué)計(jì)數(shù)法
print(3e3)  -- 3000.0-- Lua 中 a ^ b 表示 a 的 b 次方
-- 如果運(yùn)算中出現(xiàn)了浮點(diǎn)數(shù),或者發(fā)生了冪運(yùn)算,那么結(jié)果就是浮點(diǎn)
print(3 ^ 2)  -- 9.0
print(3 * 3)  -- 9-- Lua 也支持 16 進(jìn)制
print(0x61)  -- 97

算術(shù)運(yùn)算

算數(shù)運(yùn)算沒啥好說的,如果是兩個整數(shù)運(yùn)算,那么結(jié)果還是整數(shù),如果出現(xiàn)了浮點(diǎn)數(shù),那么結(jié)果為浮點(diǎn)數(shù)。

print(1 + 2, 1 + 2.)  -- 3 3.0
print(1 * 2, 1 * 2.)  -- 2 2.0
print(1 - 2, 1 - 2.)  -- -1 -1.0
print(13 % 5, 13. % 5)  -- 3 3.0

但是除法例外,兩個數(shù)相除的結(jié)果一定為浮點(diǎn)數(shù)。

print(3 / 2, 4 / 2, 4 / 2.)  -- 1.5	2.0	2.0

Lua 還提供了地板除,會對商向下取整,這是在 Lua5.3 中引入的。

print(3 // 2, 4 // 2)  -- 1	2
-- 另外,如果里面出現(xiàn)了浮點(diǎn),那么即使是地板除,也一樣會得到小數(shù)
print(4 // 2.)  -- 2.0-- 雖然是浮點(diǎn),但結(jié)果是 1.0, 相當(dāng)于還是有向下取整的效果
print(4 // 2.5)  -- 1.0

當(dāng)然 Lua 還有冪運(yùn)算,使用 ^ 表示。

print(3 ^ 4)  -- 81.0
print(3e4)  -- 30000.0

只要出現(xiàn)了冪運(yùn)算,得到的一定是浮點(diǎn)數(shù)。

位運(yùn)算

數(shù)值之間還有關(guān)系運(yùn)算,但比較簡單,這里就不贅述了。只是需要注意:不等于在其它語言中都是 !=,而在 Lua 中是 ~=。

位運(yùn)算和主流編程語言也是比較類似,尤其是 Python,感覺 Lua 的很多設(shè)計(jì)都和 Python 比較相似。

-- 按位與 &
print(15 & 20)  -- 4
-- 按位或 |
print(15 | 20)  -- 31
-- 按位異或 ~, 在其它語言中是 ^,在 Lua 中是 ~
print(15 ~ 20)  -- 27
-- 取反, 取反的話也是 ~
print(~20)  --  -21-- 左移
print(2 << 3)  -- 16
-- 右移
print(16 >> 2)  -- 4

以上這些操作符是在 5.3 當(dāng)中才提供的,如果是之前的版本,則不能使用這些操作符。

數(shù)學(xué)庫

Lua 也提供了一個數(shù)學(xué)庫,叫做 math,里面定義了一些用于計(jì)算的函數(shù),比如:sin、cos、tan、asin、floor、ceil 等等。

在這里插入圖片描述

這個在用的時候直接通過 IDE 提示,或者查詢文檔即可,這里就不演示了。

Lua 的字符串

下面我們看看 Lua 的字符串,字符串既可以使用雙引號、也可以使用單引號。注意:Lua 的字符串是不可變量,不能本地修改,如果想修改只能創(chuàng)建新的字符串。

name = "komeiji satori"
print(name) -- komeiji satori-- 使用 # 可以獲取其長度
print(#name, #"name") -- 14	4-- 使用 .. 可以將兩個字符串連接起來
print("aa" .. "bb") -- aabb
print("name: " .. name) -- name: komeiji satori-- .. 的兩邊可以沒有空格,但為了規(guī)范,建議前后保留一個空格
-- 另外 .. 前后還可以跟數(shù)字,會將數(shù)字轉(zhuǎn)成字符串
print("abc" .. 3, 3 .. 4, 3 .. "abc") -- abc3	34	3abc
-- 另外如果 .. 的前面是數(shù)字的話,那么 .. 的前面必須有空格
-- 也就是寫成類似于 3 .. 的形式,不可以寫 3..
-- 因?yàn)?3 后面如果直接出現(xiàn)了 . 那么這個 . 會被當(dāng)成小數(shù)點(diǎn)來解釋

另外如果 .. 的前面是數(shù)字的話,那么 .. 的前面必須有空格,也就是寫成類似于 3 .. 的形式,不可以寫 3..。因?yàn)?3 后面如果直接出現(xiàn)了 .,那么這個 . 會被當(dāng)成小數(shù)點(diǎn)來解釋。

Lua 內(nèi)部也支持多行字符串,使用[[]]表示。

msg = [[你好呀你在什么地方呀你吃了嗎
]]print(msg)
--[[你好呀你在什么地方呀你吃了嗎]]

字符串和數(shù)值的轉(zhuǎn)換

Lua 中字符串可以和數(shù)值相加,也可以相互轉(zhuǎn)換。

-- 如果字符串和整數(shù)運(yùn)算,那么得到的是浮點(diǎn)數(shù)
-- 你可以認(rèn)為只有整數(shù)和整數(shù)運(yùn)算才有可能得到整數(shù),而字符串不是整數(shù)
print("10" + 2)  -- 12.0
print("10.1" + 2)  -- 12.1-- 調(diào)用 tonumber 函數(shù)可以將字符串顯式地轉(zhuǎn)為整數(shù)
print(type(tonumber("10")))  -- number
print(tonumber("10") + 2)  -- 12-- 如果轉(zhuǎn)化失敗,那么結(jié)果為 nil
print(tonumber("ff"))  -- nil-- 當(dāng)然有些時候我們的數(shù)字未必是 10 進(jìn)制,比如上面的 ff,它可以是 16 進(jìn)制
-- 如果需要進(jìn)制,那么就給 tonumber 多傳遞一個參數(shù)即可
print(tonumber("ff", 16))  -- 255
print(tonumber("11101", 2))  -- 29
print(tonumber("777", 8))  -- 511-- 8 進(jìn)制,允許出現(xiàn)的最大數(shù)是 7,所以轉(zhuǎn)化失敗,結(jié)果為 nil
print(tonumber("778", 8))  -- nil-- 數(shù)值轉(zhuǎn)成字符串,則是 tostring
print(tostring(100) == "100")  -- true
print(tostring(100) == 100)  -- false
print(tostring(3.14) == "3.14")  -- true

所以數(shù)值和字符串是可以相加的,當(dāng)然相減也可以,會將字符串轉(zhuǎn)成浮點(diǎn)數(shù)。也可以判斷是否相等或者不相等,這個時候會根據(jù)類型判斷,不會隱式轉(zhuǎn)化了,由于兩者類型不一樣,直接不相等。但兩者無法比較大小,只能判斷是否相等或者不等,因?yàn)?2 < 15 但 “2” > “15”,所以為了避免混淆,在比較的時候 Lua 不會隱式轉(zhuǎn)換、加上類型不同也無法比較大小,因此直接拋異常。

字符串標(biāo)準(zhǔn)庫

Lua 處理字符串還可以使用一個叫 string 的標(biāo)準(zhǔn)庫,這個標(biāo)準(zhǔn)庫也是內(nèi)嵌在解釋器里面,我們直接通過 string.xxx 即可使用。下面就來看看 string 這個標(biāo)準(zhǔn)庫都提供了哪些函數(shù)吧,補(bǔ)充一下 Lua 的字符串是以字節(jié)為單位的,不是以字符為單位的。因此 string 的大部分函數(shù)不適合處理中文(除了少數(shù)例外),如果要處理中文,可以使用后面介紹的 utf8。

-- 查看字符串的長度
print(string.len("abc"), #"abc")  -- 3	3
-- 一個漢字占三個字節(jié),默認(rèn)是以字節(jié)為單位的,計(jì)算的是字節(jié)的個數(shù)
print(string.len("古明地覺"), #"古明地覺")  -- 12	12-- 重復(fù)字符串 n 次
print(string.rep("abc", 3))  -- abcabcabc
-- 如果是單純的重復(fù)字符串的話,也可以對中文操作,因?yàn)椴簧婕白址木植拷厝?print(string.rep("古明地覺", 3))  -- 古明地覺古明地覺古明地覺-- 字符串變小寫,可以用于中文,但是沒意義
print(string.lower("aBc"))  -- abc
print(string.lower("古明地覺"))  -- 古明地覺-- 同理還有轉(zhuǎn)大寫
print(string.upper("aBc"))  -- ABC
print(string.upper("古明地覺"))  -- 古明地覺-- 字符串翻轉(zhuǎn),這個不適合中文
print(string.reverse("abc"))  -- cba
print(string.reverse("古明地覺"))  -- ��謎厘椏�
-- 我們看到中文出現(xiàn)了亂碼,原因就是這個翻轉(zhuǎn)是以字節(jié)為單位從后向前翻轉(zhuǎn)
-- 而漢字占 3 個字節(jié),需要以 3 個字節(jié)為單位翻轉(zhuǎn)-- 字符串截取,注意:Lua 中索引是從 1 開始的
-- 結(jié)尾也可以寫成 -1,并且字符串截取包含首尾兩端
print(string.sub("abcd", 1, -1))  -- abcd
print(string.sub("abcd", 2, -2))  -- bc
-- 可以只指定開頭,不指定結(jié)尾,但是不可以開頭結(jié)尾都不指定
print(string.sub("abcd", 2))  -- bcd-- 同樣不適合中文,除非你能準(zhǔn)確計(jì)算字節(jié)的數(shù)量
print(string.sub("古明地覺", 1, 3))  -- 古
print(string.sub("古明地覺", 1, 4))  -- 古�
-- 超出范圍,就為空字符串
print(string.sub("古明地覺", 100, 400) == "")  -- true-- 將數(shù)字轉(zhuǎn)成字符
print(string.char(97))  -- a
-- 如果是多個數(shù)字,那么在轉(zhuǎn)化成字符之后會自動拼接成字符串
print(string.char(97, 98, 99))  -- abc-- 字符轉(zhuǎn)成數(shù)字,默認(rèn)只轉(zhuǎn)換第 1 個
print(string.byte("abc"))  -- 97
-- 可以手動指定轉(zhuǎn)換第幾個字符
print(string.byte("abc", 2))  -- 98
print(string.byte("abc", -1))  -- 99
-- 超出范圍,那么返回 nil
print(string.byte("abc", 10) == nil)   -- nil
-- 轉(zhuǎn)換多個字符也是可以的,這里轉(zhuǎn)化索引為 1 到 -1 之間的所有字符
print(string.byte("abc", 1, -1))  -- 97	98	99
-- 越界也沒事,有幾個就轉(zhuǎn)化幾個
print(string.byte("abc", 1, 10))  -- 97	98	99
-- 另外,這里是返回了多個值,我們也可以用多個變量去接收
a, b, c = string.byte("abc", 1, 10)
print(a, b, c)  -- 97	98	99-- 關(guān)乎 Lua 返回值,由于涉及到了函數(shù),我們后面會說
-- 字符串的格式化,格式化的風(fēng)格類似于 C
print(string.format("name = %s, age = %d, number = %03d", "古明地覺", 17, 1))  -- name = 古明地覺, age = 17, number = 001-- 字符串的查找,會返回兩個值,分別是開始位置和結(jié)束位置
print(string.find("abcdef", "de"))  -- 4	5
-- 不存在則為 nil
print(string.find("abcdef", "xx"))  -- nil-- 字符串的全局替換,這個替換可以用中文,返回替換之后的字符串和替換的個數(shù)
print(string.gsub("古名地覺 名名 那么可愛", "名", "明"))  -- 古明地覺 明明 那么可愛	3
-- 我們同樣可以使用返回值去接
new_str, count = string.gsub("古名地覺 名名 那么可愛", "名", "明")
print(new_str)  -- 古明地覺 明明 那么可愛

關(guān)于處理 ASCII 字符,string 庫為我們提供了以上的支持,可以看到支持的東西還是比較少的,因?yàn)?Lua 的源碼總共才兩萬多行,這就決定了它沒辦法提供過多的功能。Lua 主要是用來和別的語言結(jié)合的,并且 string 庫提供的東西也不少了。

下面來看看 utf-8,我們說 string 庫不是用來處理 unicode 字符的,如果處理 unicode 字符的話,需要使用 utf8 這個庫。

-- Lua 中存儲 unicode 字符使用的編碼是 utf-8
-- 計(jì)算長度
print(utf8.len("古明地覺"))  -- 4-- 類似于 string.byte,這兩個可以通用
print(utf8.codepoint("古明地覺", 1, -1))  -- 21476	26126	22320	35273-- 類似于 string.char,這兩個可以通用
print(utf8.char(21476, 26126, 22320, 35273))  -- 古明地覺-- 截取,使用 string.sub,但不同字符占的字節(jié)大小可能不一樣,這時候怎么截取呢
-- 可以通過 utf8.offset 計(jì)算出,偏移到第 n 個字符的字節(jié)量
print(string.sub("古明地覺", utf8.offset("古明地覺", 2)))  -- 明地覺
print(string.sub("古明地覺", utf8.offset("古明地覺", -2)))  -- 地覺-- 遍歷,遍歷使用了 for 循環(huán),我們后面說,現(xiàn)在先看一下
for i, c in utf8.codes("古a明b地c覺") doprint(i, c, utf8.char(c))--[[1	21476	古4	97	    a5	26126	明8	98	    b9	22320	地12	99	    c13	35273	覺]]
end

以上便是 Lua 處理字符串的一些操作, 盡管功能提供的不是非常的全面,但這與 Lua 的定位有關(guān)。

Lua的控制結(jié)構(gòu)

控制結(jié)構(gòu)主要有兩種:條件語句和循環(huán)語句。

條件語句

-- 單獨(dú)的 if
if condition thenstatement
end-- if 和 else
if condition thenstatement
elsestatement
end-- if elseif else
-- 注意:是 elseif,不是 else if,else 和 if 之間需要連起來
if condition thenstatement
elseif condition thenstatement
elseif condition thenstatement
elsestatement
end    

if 和 elseif 后面必須加上一個 then,類似于 Python 中必須加上一個冒號一樣,但是 else 則不需要 then。另外每個 if 語句,在結(jié)尾處必須有一個 end,來標(biāo)志這個 if 語句塊的結(jié)束。不過既然結(jié)尾有 end,那么 Lua 中也就不需要縮進(jìn)了,但 Python 則是必須嚴(yán)格遵循縮進(jìn)規(guī)范,而 Lua 則不被縮進(jìn)約束。但還是那句話,為了代碼的可讀性還是建議按照 Python 的規(guī)范來編寫。

a = 85if a < 60 thenprint("不及格")
elseif a < 85 thenprint("及格")
elseif a < 100 thenprint("優(yōu)秀")
elseif a == 100 thenprint("滿分")
elseprint("無效的分?jǐn)?shù)")
end
-- 優(yōu)秀

循環(huán)while語句

while condition dostatement
end

repeat … until

repeat … until 說白點(diǎn)就是一直重復(fù)做,直到滿足某個條件停下來。

i =1 
sum = 0-- 不斷的執(zhí)行 sum = sum + 1 和 i = i + 1,直到滿足 i >= 10 的時候停下來
repeatsum = sum + ii = i + 1
until i >= 10print(string.format("sum = %d", sum))  -- sum = 45

循環(huán) for 語句

break

break 用于跳出循環(huán)體,可以用于 for、while、repeat,注意:沒有 continue。

and 和 or

如果需要多個判斷條件,那么可以使用 and 和 or 進(jìn)行連接。

username = "zpli"
password = "123456"if username == "zpli" and password == "123456" thenprint("歡迎來到避難小屋")
elseprint("用戶名密碼不對")
end
-- 歡迎來到避難小屋-- 另外 Lua 中還有 not 表示取反,得到布爾值
-- 這里著重強(qiáng)調(diào)一點(diǎn),在 Lua 中只有 false 和 nil 才為假,其它全部為真
-- 這里和 Python 不一樣,在 Python 中 0、"" 是假,但在 Lua 中是真
print(not 0)  -- false
print(not "")  -- false
print(not not "")  -- true
-- 0 和 "" 為真,所以使用 not 得到假,兩個 not 得到真

以上我們就介紹了 Lua 的控制結(jié)構(gòu),比較簡單。

Lua的表

下面來看看 Lua 的表(Table),表是 Lua 語言中最主要(事實(shí)上也是唯一)的數(shù)據(jù)結(jié)構(gòu),表既可以當(dāng)做數(shù)組來用,也可以當(dāng)成哈希表來用。這個和 Python 的字典非常類似,比如我們之前查看變量類型的 math.type,本質(zhì)上就是以字符串 “type” 來檢索表 math。而在 Python 中,比如調(diào)用 math.sin,本質(zhì)也是從 math 模塊的屬性字典里面查找 key 為 “sin” 對應(yīng)的 value。

然后看看在 Lua 中如何創(chuàng)建表。

-- 類似于 Python 的字典,Lua 中創(chuàng)建表直接使用大括號即可
t = {}
-- 返回的是表的一個引用
print(t)  -- table: 00000000010b9160
-- 類型為 table
print(type(t) == "table")  -- true

在這里我們需要介紹一下 Lua 的變量,在 Lua 中分為全局變量和局部變量,這兩者我們會在函數(shù)中細(xì)說。總之目前創(chuàng)建的都是全局變量,其有一個特點(diǎn):

-- 對于沒有創(chuàng)建的變量,可以直接打印,結(jié)果是一個 nil
print(a)  -- nil-- c 這個變量沒有創(chuàng)建,因此是 nil,那么 d 也是 nil
d = c
print(d)  -- nil-- 所以我們看到程序中明明沒有這個變量,但是卻可以使用,只不過結(jié)果為 nil
-- 那如果我們將一個已經(jīng)存在的變量賦值為 nil,是不是等于沒有創(chuàng)建這個變量呢?
-- 答案是正確的,如果將一個變量賦值為 nil,那么代表這個變量對應(yīng)的內(nèi)存就會被回收
name = "shiina mashiro"
name = nil  -- "shiina mashiro" 這個字符串會被回收

之所以介紹全局變量這個特性,是因?yàn)樵诒碇?#xff0c;nil 是一個大坑,我們往下看。

a = {}a["name"] = "古明地覺"
a["age"] = 16-- 打印 a 只是返回一個引用
print(a)  -- table: 00000000000290e0
print(a["name"], a["age"])  -- 古明地覺	16-- 更改表的元素
-- table 類似于哈希表,key 是不重復(fù)的,所以重復(fù)賦值相當(dāng)于更新
a["age"] = a["age"] + 1
print(a["age"])  -- 17-- 全局變量也是通過 table 存儲的,我們可以給一個變量不斷地賦值,賦上不同類型的值
a["age"] = 18
print(a["age"])  -- 18
a["age"] = "十六"
print(a["age"])  -- 十六-- 創(chuàng)建 table 返回的是一個引用
b = a
-- 此時的 b 和 a 指向的是同一個 table,修改 b 會影響到 a
b["name"] = "satori"
print(a["name"])  -- satori-- 賦值為 nil,等價(jià)于回收對象
a = nil 
-- 但是只將 a 賦值為nil,顯然還不夠,因?yàn)檫€有 b 在指向上面的 table
b = nil 
-- 這樣的話,table 就被回收了

Lua 的 table 既可以做哈希表,也可以當(dāng)做數(shù)組,有興趣可以看 Lua 的源代碼,非常的精簡。下面來看看 table 如何當(dāng)成數(shù)組來使用:

a = {}for i = 1, 10 doa[i] = i * 2
endprint(a[3])  -- 6-- table 的底層是一個結(jié)構(gòu)體,里面實(shí)現(xiàn)了哈希表和數(shù)組兩種結(jié)構(gòu)
-- 如果 key 是整型,那么會通過數(shù)組的方式來存儲,如果不是,會使用哈希表來存儲
-- 注意:如果當(dāng)成數(shù)組使用,那么索引也是從 1 開始的-- 此時是通過哈希表存儲的
a["x"] = 233
print(a["x"])  -- 233-- 除了a["x"]這種方式,還可以使用a.x,這兩者在 Lua 中是等價(jià)的
print(a.x)  -- 233-- a["name"] 和 a.name 是等價(jià)的,但是和 a[name] 不是等價(jià)的
-- 因?yàn)?name 是一個變量,而 name = "x",所以結(jié)果是 a["x"] 或者 a.x
a["name"] = "椎名真白"
name = "x"
print(a["name"], a.name, a[name])  -- 椎名真白	椎名真白	233

然后是關(guān)于整數(shù)和浮點(diǎn)數(shù)的一個坑,來看一下。

a = {}a[2] = 123
print(a[2.0])  -- 123a[2.0] = 456
print(a[2])  -- 456-- 所以這兩者是等價(jià)的,因?yàn)?2.0 會被隱式轉(zhuǎn)化為 2,事實(shí)上在 Python 的字典中也有類似的現(xiàn)象
-- d = {}; d[True] = 1; d[1] = 2; d[1.0] = 3; print(d)
-- 上面那行代碼在 Python 里面執(zhí)行一下,看看會發(fā)生什么-- 但對于字符串則不一樣,因?yàn)?2 和 "2" 不相等
a = {}
a[2] = 123
a["2"] = 456
print(a[2], a["2"])  -- 123	456-- 如果訪問表中一個不存在的 key 呢?
print(a["xxx"])  -- nil-- 我們看到得到的是一個 nil
-- 顯然我們想到了,如果將一個 key 對應(yīng)的值顯式地賦值為 nil,那么也等價(jià)于刪除這個元素
a[2] = nil 

表構(gòu)造器

估計(jì)有人目前對 table 即可以當(dāng)數(shù)組又可以當(dāng)哈希表會感到困惑,別著急我們會慢慢說。目前創(chuàng)建表的時候,都是創(chuàng)建了一張空表,其實(shí)在創(chuàng)建的時候是可以指定元素的。

a = {"a", "b", "c" }
print(a[1], a[2], a[3])  -- a	b	c
-- 我們看到如果不指定 key,那么表的元素是通過數(shù)組存儲的,這種存儲方式叫做 "列表式(list-style)"
-- 索引默認(rèn)是 1 2 3 4...-- 此外,還可以這么創(chuàng)建
b = {name="mashiro", age=18 }
print(b["name"], b["age"])  -- mashiro	18
-- 第二種方式是通過哈希表存儲的,這種存儲方式叫做"記錄式(record-style)"-- 但如果存儲的 key 是數(shù)字或者特殊字符,那么需要使用 [] 包起來
b = {["+"] = "add", [3] = "xxx"}  -- 必須使用 ["+"] 和 [3],不能是單獨(dú)的 + 和 3
-- 同理獲取也只能是 b["+"] 和 b[3],不可以是 b.+ 和 b.3
print(b["+"], b[3])  -- add xxx-- 表也是可以嵌套的
a["table"] = b
print(a["table"]["+"])  -- add-- 此外,兩種方式也可以混合使用
mix = {'a', name='mashiro', 'b', age=18 }
print(mix[1], mix[2])  -- a	b
print(mix["name"], mix["age"])  -- mashiro	18-- 這里有必要詳細(xì)說明一下,即使是混合使用
-- 如果沒有顯式地指定 key、也就是列表式,那么會以數(shù)組的形式存儲,索引默認(rèn)是 1 2 3...
-- 所以 a[1] 是 'a', a[2] 是 'b'-- 如果是這種情況呢?
mix = {'a', [2] = 1 }
print(mix[2])  -- 1
mix = {'a', 'b', [2] = 1 }
print(mix[2])  -- b
-- 解釋一下,首先對于單個標(biāo)量來說,默認(rèn)就是用數(shù)組存儲的,索引就是 1 2 3...
-- 但我們在通過記錄式設(shè)置的時候,對應(yīng)的 key 使用的如果也是數(shù)組的索引,那么記錄式中設(shè)置的值會被頂?shù)?/span>
--[[
比如:mix = {'a', [2] = 1 }, 數(shù)組的最大索引是 1,所以 [2] = 1 是沒有問題的
但是 mix = {'a', 'b', [2] = 1 },數(shù)組最大索引是 2,所以 [2] = 1 會被頂?shù)?#xff0c;因?yàn)闆_突了
]]-- 事實(shí)上 mix = {'a', 'b', [2] = 1 } 這種方式就等價(jià)于 mix = {[1] = 'a', [2] = 'b', [2] = 1 }
-- 如果 key 是整型,那么也通過數(shù)組存儲, 否則通過哈希表存儲
-- 只不過我們手動指定 [2] = 1 會先創(chuàng)建,然后被 [2] = 'b' 頂?shù)袅?/span>
a = {'a', [1] = 1 }
print(a[1])  -- 'a'
a = {[1] = 1, 'a'}
print(a[1])  -- 'a'
-- 無論順序如何,a[1] 都會是 'a'

估計(jì)有人還有疑問,那就是a = {}; a[1] = 1; a[100] = 100或者a = {1, [100] = 100},如果這樣創(chuàng)建的話,那中間的元素是什么?因?yàn)槲覀冋f key 是整型則以數(shù)組存儲,而數(shù)組又是連續(xù)的存儲的空間,而我們只創(chuàng)建了兩個元素,索引分別是 1 和 100,那么其它元素是以什么形式存在呢?帶著這些疑問,我們先往下看。

數(shù)組、列表和序列

現(xiàn)在我們知道了如果想表示常見的數(shù)組、或者列表,那么只需要使用整型作為索引即可。而且在 Lua 的 table 中,可以使用任意數(shù)字作為索引,只不過默認(rèn)是從 1 開始的,Lua 中很多其它機(jī)制也遵循此慣例。

但是table的長度怎么算呢?我們知道對字符串可以使用 #,同理對 table 也是如此。

a = {1, 2, 3, name = 'mashiro', 'a' }
print(#a)  -- 4
-- 但是我們看到結(jié)果為 4,可明明里面有 5 個元素啊
-- 因?yàn)?# 計(jì)算的是索引為整型的元素的個數(shù),更準(zhǔn)確的說 # 計(jì)算的是使用數(shù)組存儲的元素的個數(shù)a = {[0] = 1, 2, 3, 4, [-1]=5}
print(#a)  -- 3
-- 此時的結(jié)果是 3,因?yàn)?0 和 -1 雖然是整型,但它們并沒有存儲在數(shù)組里
-- 因?yàn)?Lua 索引默認(rèn)從 1 開始,如果想要被存儲的數(shù)組里面,那么索引必須大于 0a = {1, 2, [3.0]="xxx", [4.1] = "aaa" }
print(#a)  -- 3
-- 這里同樣是 3,因?yàn)?3.0 會被隱式轉(zhuǎn)化為 3,因此數(shù)組里面有 3 個元素,但是 4.1 不會

所以我們看到,# 計(jì)算的是存儲在數(shù)組里面的元素,也就是 table 中索引為正整數(shù)的元素,但真的是這樣嗎?

首先對于數(shù)組中存在nil的 table,使用 # 獲取長度是不可靠的,它只適用于數(shù)組中所有元素都不為 nil 的 table。事實(shí)上,將 # 應(yīng)用于獲取 table 長度一直飽受爭議,以前很多人建議如果數(shù)組中存在 nil,那么使用 # 操作符直接拋出異常,或者說擴(kuò)展一下 # 的語義。然而這些建議都是說起來容易做起來難,主要是在 Lua 中數(shù)組實(shí)際上是一個 table,而 table 的長度不是很好理解。

我們舉例說明:

a = {1, 2, 3, 4 }
a[2] = nil
-- 很容易得出這是一個長度為 4,第二個元素為 nil 的 table
print(#a)  -- 4-- 但是下面這個例子呢?沒錯,就是我們之前說的
b = {}
b[1] = 1
b[100] = 100
-- 是否應(yīng)該認(rèn)為這是一個具有 100 個元素,其中 98 個元素為 nil 的 table 呢?
-- 如果我們再將 a[100] 設(shè)置成 nil,該列表長度又是多少呢?是 100、99 還是 1 呢
print(#b)  -- 1
-- Lua 作者的想法是,像 C 語言使用 \0 作為字符串的結(jié)束一樣,Lua 可以使用 nil 來隱式地表示 table 的結(jié)束
-- 可問題是 a 的第二個元素也是 nil 啊,為什么長度是 4 呢-- 總之在 table 中出現(xiàn)了 nil,那么 # 的結(jié)果是不可控的
-- 有可能你多加一個 nil,結(jié)果就變了。當(dāng)然,不要去探究它的規(guī)律,因?yàn)檫@沒有意義
-- 總之不要在 table 中寫 nil,在 table 中寫 nil 是原罪。不管是列表式、還是記錄式,都不要寫 nil,因?yàn)樵O(shè)置為 nil,就表示刪除這個元素-- 回到 b 這個 table 中,我們說它的長度為 1
print(#b)  -- 1
-- 但是數(shù)組中確實(shí)存在索引為 100 的元素
print(b[100])  -- 100

所以對 b 這個 table,其中數(shù)組到底是怎么存儲的,其實(shí)沒必要糾結(jié),就當(dāng)成索引為 2 到索引為 99 的元素全部是 nil 即可,但計(jì)算長度的時候是不準(zhǔn)的,總之 table 中最好不要出現(xiàn) nil。

遍歷表

我們可以使用 for 循環(huán)去遍歷 table。

a = {"a", "b", name="mashiro", "c", age=18, "d" }-- for 循環(huán)除了 for i = start, end, step 這種方式之外,還可以作用在表上面
-- 只不過需要使用 pairs 將 table 包起來:for k, v in pairs(t)
for index, value in pairs(a) doprint(index, value)--[[1	    a2	    b3	    c4	    dage	    18name    mashiro]]
end
-- 這里的 for 循環(huán)中出現(xiàn)了兩個循環(huán)變量,分別表示索引和值
-- 如果只有一個變量,那么得到的是索引,或者哈希表的 key
-- 然后遍歷的時候先遍歷數(shù)組(按照索引從小到大輸出),然后遍歷哈希表(不保證順序)-- 除了 pairs,還有 ipairs,ipars 是只遍歷存在于數(shù)組里面的元素
a = {[4] = "a", [3] = "b", name="mashiro", "c", age=18, [2] = "d" }
for index, value in ipairs(a) doprint(index, value)--[[1	c2	d3	b4	a]]
end
-- 打印按照索引從小到大打印,但是不建議這么創(chuàng)建table

如果 table 中出現(xiàn)了 nil,那么使用 for 循環(huán)去遍歷會發(fā)生什么奇特的現(xiàn)象呢?

-- 不過在此之前,還是先來看一個坑向的
a = {[3] = 1, 'a', 'b', 'c' }
-- 這個時候 a[3] 是多少呢?
print(a[3])  -- c
-- 我們說只要是列表式,都是從 1 開始,所以 [3] = 1 最終會被 [3] = 'c' 所頂?shù)?/span>
-- 上面的賦值等價(jià)于 a = {[3] = 1, [1] = 'a', [2] = 'b', [3] = 'c'}
-- 因?yàn)槿绻恢付?key,那么 Lua 會按照 1 2 3 4 ··· 自動給一個 key(準(zhǔn)確來說是索引),因?yàn)樗鼈兇嬖跀?shù)組中-- 再來看看 table 中出現(xiàn)了 nil,for 循環(huán)會如何表現(xiàn)
a = {'a', nil, 'b', 'c' }
print(#a)  -- 4for index, value in ipairs(a) doprint(index, value)--[[1   a]]
end
-- 長度雖然是 4(當(dāng)然我們知道這不準(zhǔn)),但在遍歷的時候一旦遇到 nil 就會終止遍歷
-- 當(dāng)然這個 nil 要是數(shù)組中的 nil,不是哈希表中的 nil
-- 但如果是 pairs,那么會遍歷值不為 nil 的所有記錄
a = {'a', nil, 'b', 'c', name=nil, age=18}
for index, value in pairs(a) doprint(index, value)--[[1	a3	b4	cage	18]]
end
-- 但我們看到值 "b" 對應(yīng)的索引是 3,盡管前面的是 nil,但畢竟占了一個坑,所以 "b" 對應(yīng)的索引是 3-- 當(dāng)然我們還可以使用獲取長度、數(shù)值遍歷的方式,當(dāng)然前提是 table 中不能出現(xiàn) nil
a = {'a', 'b', 123, 'xx' }
for idx = 1, #a doprint(a[idx])--[[ab123xx]]
end

表標(biāo)準(zhǔn)庫

表的標(biāo)準(zhǔn)庫提供一些函數(shù),用于對表進(jìn)行操作,注意:這個標(biāo)準(zhǔn)庫也叫 table。

a = {10, 20, 30 }
print(a[1], a[2], a[3])  -- 10	20	30-- 使用 table.insert 可以插入一個值
-- 接收參數(shù)為:table 插入位置 插入的值
table.insert(a, 2, "xxx")
print(a[1], a[2], a[3], a[4])  -- 10   xxx	20	30
-- 如果不指定位置,那么默認(rèn)會添加在結(jié)尾
-- 此時傳遞兩個參數(shù)即可:table 插入的值
table.insert(a, "古明地覺")
print(a[#a])  -- 古明地覺-- 既然有 insert,那么就會有 remove
-- 接收參數(shù):table 移除的元素的位置(索引)
print(a[1], a[2], a[3], a[4], a[5])  -- 10	xxx	20	30
table.remove(a, 3)
print(a[1], a[2], a[3], a[4], a[5])  -- 10	xxx	30	古明地覺    nil-- 我們看到使用 remove 之后,后面的元素會依次向前移動,因此無需擔(dān)心會出現(xiàn) nil 什么的
-- 不過這也說明了,remove 的效率不是很高,因?yàn)樯婕暗皆氐囊苿?/span>
-- 但 table 中的函數(shù)都是 C 實(shí)現(xiàn)的,也是很快的,因此也不用太擔(dān)心-- 另外在 lua5.3 中,還提供了一個 move 函數(shù)
-- table.move(table, start, end, target),表示將 table 中 [start, end] 之間的元素移動到索引為 target 的位置上
-- 也是 start 位置的元素跑到 target 處,start + 1 -> target + 1、 end -> target + end - start
t = {1, 2, 3, 4}
table.move(t, 2, #t, 3)
print(t[1], t[2], t[3], t[4], t[5])  -- 1	2	2	3	4
-- 很好理解,{1 2 3 4} 中索引為 [2, #t],移動到索引為 3 的位置上,因此結(jié)果是1 2 2 3 4,結(jié)果會多出一個-- 這里的 move 實(shí)際上是將一個值從一個地方拷貝 copy 到另一個地方
-- 另外,我們除了可以將元素移動到 table 本身之外,還可以移動到另一個 table
t1 = {"a", "b", "c", "d" }
t2 = {"x", "y" }
-- 表示將 t1 中 [2, #t1] 的元素移動到 t2 中索引為 2 的地方
table.move(t1, 2, #t1, 2, t2)
for idx = 1, #t2 doprint(t2[idx])--[[xbcd]]
end-- table 標(biāo)準(zhǔn)庫中還提供了 concat 函數(shù),會將表里面的元素拼接起來
a = {1, 2, "xxx", 3, "aaa" }
print(table.concat(a))  -- 12xxx3aaa

來個思考題吧

a = "b"
b = "a"t = {a = "b", [a] = b }
print(t.a, t[a], t[t.b], t[t[b]])-- 上面的 print 會打印出什么呢?我們分析一下,首先看 t 這個表,其中 a = "b" 無需多說
-- 關(guān)鍵是 [a] = b,我們說 a 和 b 都是變量,并且 a = "b"、b = "a", 所以結(jié)果等價(jià)于 ["b"] = "a", 即:b = "a"
-- 因此這里的 t 可以看做是 {a = "b", b = "a"}-- 那么 t.a 顯然是 "b",t[a]等于t["b"],因此結(jié)果是 "a"
-- t.b 結(jié)果是 "a",那么 t[t.b] 等于是 t["a"],所以結(jié)果是 "b"
-- t[b] -> t["a"] -> "b",那么 t[t[b]] -> t["b"] -> "a",因此結(jié)果是 "a"
-- 所以 print 會打印出: "b" "a" "b" "a"-- 下個問題
a = {}
a.a = a
print(a)  -- table: 0000000000d98ef0
print(a.a)  -- table: 0000000000d98ef0
print(a.a.a)  -- table: 0000000000d98ef0-- 打印的都是一樣的,我們說 Lua 中的 table 返回的一個引用
-- a.a = a,本身顯然陷入了套娃的狀態(tài)

以上就是 Lua 的表,總的來說并不復(fù)雜,只是要注意里面不要出現(xiàn) nil 就好。然后 table 采用了兩種數(shù)據(jù)結(jié)構(gòu):數(shù)組和哈希表,它即可以當(dāng)成數(shù)組來用,也可以當(dāng)成哈希表來用,當(dāng)然也可以混合使用。如果 key 是整數(shù),那么存在數(shù)組中,否則存在哈希表中。

http://www.risenshineclean.com/news/43155.html

相關(guān)文章:

  • 西寧網(wǎng)站建設(shè)的公司哪家好免費(fèi)二級域名建站
  • 百度wap網(wǎng)站建設(shè)cdq百度指數(shù)
  • 惠州企業(yè)自助建站自己怎么創(chuàng)建網(wǎng)站
  • 臨沂購買模板建站網(wǎng)頁首頁設(shè)計(jì)圖片
  • 深圳教育網(wǎng)站設(shè)計(jì)公司鄭州seo顧問培訓(xùn)
  • java做網(wǎng)站沒有php好嗎360瀏覽器網(wǎng)頁版入口
  • 網(wǎng)站查詢信息愛站網(wǎng)關(guān)鍵字挖掘
  • wordpress建設(shè)網(wǎng)站石家莊全網(wǎng)seo
  • 美國網(wǎng)站服務(wù)器營銷活動推廣策劃
  • 做網(wǎng)站seo優(yōu)化線上營銷策略都有哪些
  • 西安手機(jī)定制網(wǎng)站建設(shè)電商網(wǎng)站平臺有哪些
  • 廣州品牌網(wǎng)站建設(shè)seo網(wǎng)站推廣與優(yōu)化方案
  • 中企動力科技股份有限公司網(wǎng)站官網(wǎng)2020十大網(wǎng)絡(luò)熱詞
  • 新手引導(dǎo)做的差的網(wǎng)站免費(fèi)建站軟件
  • 動態(tài)網(wǎng)站完整版百度pc網(wǎng)頁版
  • ??诜慨a(chǎn)網(wǎng)站建設(shè)最近發(fā)生的熱點(diǎn)事件
  • 廣州市公司網(wǎng)站建設(shè)公司在線培訓(xùn)app
  • 網(wǎng)站 建設(shè)需求上海aso蘋果關(guān)鍵詞優(yōu)化
  • 網(wǎng)站域名 設(shè)置快速網(wǎng)站seo效果
  • 怎樣做網(wǎng)站首頁圖片變換seo研究中心培訓(xùn)機(jī)構(gòu)
  • 做俄羅斯外貿(mào)的網(wǎng)站設(shè)計(jì)網(wǎng)址域名ip查詢
  • 潮汕網(wǎng)站建設(shè)antnw網(wǎng)頁設(shè)計(jì)需要學(xué)什么
  • 網(wǎng)站加速服務(wù)武漢seo網(wǎng)絡(luò)優(yōu)化公司
  • 做網(wǎng)站的學(xué)什么代碼海外推廣服務(wù)
  • 麗水微信網(wǎng)站建設(shè)哪家好滄州網(wǎng)絡(luò)推廣公司
  • 建立網(wǎng)站的詳細(xì)步驟營銷模式有哪些 新型
  • 香港空間建網(wǎng)站百度一下百度網(wǎng)頁版
  • html網(wǎng)站要怎么做簡單制作html靜態(tài)網(wǎng)頁
  • 眉山市住房和城鄉(xiāng)建設(shè)局網(wǎng)站西安推廣平臺排行榜
  • 還有哪些免費(fèi)的網(wǎng)站可以做H5優(yōu)化推廣什么意思