# 簡介 & 安裝 ## 介紹 Lua Lua 在葡萄牙語是月亮的意思,是一個輕量級簡單且可嵌入的程式語言。其目的就是為了**更容易嵌入其他程式語言當中**。核心主要是做基本的功能,所以啟動飛快。 > [!Note]可嵌入式語言 其實就是可以跟其他程式語言互相溝通,常常用於C / Java 中,可以少寫很多東西,也可以用在 Python 中,但實際效應不大。 ## 安裝 Lua 直接上[Lua官網](https://www.lua.org/)載資源包或是終端機打指令。 ## 使用編譯器 Visual Studio Code ## 第一個 Lua 檔案 學習每個語言一開始應該都是 Hello, World ```lua print("Hello, World") ``` > Lua 有一個神奇的寫法,字串輸出可以不用括號 ```lua print "Hello, World" ``` # 基礎語法 ## Lua 先備知識 ### 1. 保留字 (Reserved Word) :::spoiler 一點點保留字 - if - elseif - else - then - and - or - not - end - true - false - nil - do - for - in - while - repeat - until - function - return - goto ::: ### 2. Chunk 是指被執行的一整個檔案,裡面會有很多block :::success > [!Note] block 其實就是上面保留字湊在一起的 - `do-end` - `function-end` - `if-then-end` - `for-end` - `while-end` - `repeat-until` etc. 可以在裡面宣告區域變數 ```lua= do local s = "Hello, world" print(s) --> "Hello, world" end print(s) --> nil ``` ::: ### 3. 語法糖 (Syntax Suger) 就是一個語言自己的獨特寫法,可以讓程式碼變得更簡潔 :::spoiler 語法糖大餐 ||還想給我偷懶,乖乖先寫正常的,後面會提到。 || ::: ## 變數定義 資料型態分成一下 8 種: | 類型 | 說明 | | ---------- | ---------------------------------- | | `nil` | 類似 `None`,表示空值或不存在的值 | | `boolean` | 布林值,有 `True` 與 `False` 之分 | | `number` | 數字型態,在模組中細分為整數(integer)與浮點數(float) | | `string` | 字串 | | `table` | 表格型態,可作為陣列(array)或映射(map)使用 | | `function` | 函式 | | `userdata` | 用於儲存檔案或其他外部資料的型態 | | `thread` | 執行緒,可用於控制函式的執行流程 | 是不是頭很痛ww,但還沒有完,因為變數也分成: * 全域 `_ENV` / `_G` (預設) * 區域 `local` 先會介紹 `string`, `number` > [!Caution]**tip**: 在 Lua 中單行註解長這樣`--`,多行則是類似長字串`--[[]]` :::success > [!Tip]字串 string 可以用 `''` 跟 `""`,而且也有支援utf-8 1. 字串長度 > Python 用 len直接無敵😁 ```lua= String.len('Lua') --> 3 utf8.len('我') --> 1 ``` 也可以利用語法糖 (syntax suger) ```lua= #'Lua' --> 3 ``` 2. 長字串 (long string) > 類似 Python 的 `r""""""` ```lua= s1 = [[ How are you? I'm fine thank you, and you? ]] ``` - 配對:利用相同的等號就可以了 ```lua= s2 = [=====[[=]]=====] --> "[=]" ``` 3. 字串連接 > 就跟其他語言一樣 ```lua= s1 = "Hello, "; s2 = "Lua" s3 = s1 + s2 -- "Hello, Lua" ``` 但有個特別的寫法,召喚語法糖 ```lua= s3 = s1 .. s2 ``` `..`之間不一定要空格,但我喜歡空格😁 4. 字串格式化 > 類似 Python 中的 format ```lua= local string = require "string" -- 引用 string string.format("Lua") ``` > [!Note] String library 是一個支援更多字串操作的函式庫 之後下面會介紹一些裡面的函式 ::: :::success > [!Tip]數字 (number) 在 Lua 中會自動轉換整數跟浮點數 ```lua= type(1) --> number type(1.0) --> number ``` 但不是沒有分別 ```lua= math.type(1) --> integer math.type(1.0) --> float ``` 1. 溢位 (overflow) Lua 5.4使用64位元的整數和浮點數(雙精度浮點數double)。 ```lua= math.type(9223372036854775807) -- => integer math.type(9223372036854775808) -- => float ``` 2. 精度丟失 浮點數表示也有極限 ```lua= 18446744073709552111 -- => 18446744073709552000 18446744073709552000 == 18446744073709552000+100 -- => true ``` 3. 字串轉數字 ```lua= tonumber("1") --> 1 ``` 4. 數字轉字串 ```lua= toString(1) --> "1" ``` 5. 自動轉型 ```lua= "1" + 2 --> 3 "1.0" .. 2 --> "1.02" ``` 也就可以把3, 4點變成語法糖寫法 ```lua= "1" + 0 --> string to int 1 .. "" --> int to string ``` ::: 在 Lua 5.4 中有加了新的類似 JavaScript 的語法 `const`、`close`(不想看得可以先跳過) :::success > [!Tip] Local Varaible Attribute (局部變數屬性) 就是可以對區域變數做一些酷酷的事情 - const:固定變數值 ```lua= do local pi<const> = math.pi --> = const pi = math.pi() pi = 3 --> attempt to assign to const variable 'pi' end ``` - close: 關閉檔案 ```lua= io = require "io" f = io.open("text.txt") print(type(f)) -- file f:close() print(type(f)) -- file (closed) ``` 也可以寫成(這個比較好) ```lua= io = require "io" do local f<close> = io.open("text.txt") end print(type(f)) -- close ``` ::: ### if-elseif-else 痾,就是拿來判斷條件的👍 > [!Caution] 有 **if** 最後都要加 `then`,則結尾要加上 `end` ```lua= if condition then -- code elseif condition then -- code else -- code end ``` **example** ```lua= s = 3 if s > 3 then print s .. "greater than 3" elseif s == 3 then print s .. "equal than 3" else print s .. "less than 3" ``` ## 迴圈 分成一下 3 種: | 類型 | 說明 | | -- | -- | |`for ... end` | 有範圍 or 迭代| | `while ... end` | 先寫終止條件 | | `repeat ... until` | 後寫終止條件 | :::success > [!Tip]for 迴圈 > 有範圍 or 迭代 1. 有範圍 > Python `for i in range(step, final [, step]):` ```lua= for i=start, final, step do -- code end ``` - `start`: 起始值 - `end`: 終止值 - `step`: 一次加多少 **example:** ```lua= for i=1, 5, 1 do print(i) end --[[ output 1 2 3 4 5 ]] ``` 2. 迭代 (iterate) > Python `for i in iterator:` ```lua= for i in iterator do -- code end ``` > [!Note] 迭代 (iterate) & 迭代器 (iterator) > `iterate`: 處理一個一個在容器裡的資料 > `iterator`: 處理一個一個在容器裡的資料的工具 **example for table:** ```lua= s = {1, 2, 3, 4,5} for k, v in ipairs(s) do print(k, v) end for k, v in pairs(s) do print(k, v) end --[[ output (兩個輸出都一樣) 1 1 2 2 3 3 4 4 5 5 ]] ``` 看起來沒有差別吧,但還是有差的 > [!Note] ipars & pairs `ipairs` : 按照key順序,直到 `nil` `pairs` : 無序的,直到遍例所有key > [!Caution] Lua 中的索引值是**從1開始不是0喔** **example for string** ```lua= s = "Lua" for i=1, #s do local c = string.sub(s, i, i) print(i, c) end for i in string.gmatch(s, '.') do print(i) end --[[ output: 1 L 2 u 3 a L u a ]] ``` > [!Note] `string.sub` 就是 Python 的 slice: `string[start: end]` ```lua= string.sub(str, start, final) -- 也可以寫成這樣 str:sub(start, final) ``` ::: - `start`: 字串切片的起始值,**記得從一開始喔** - `final`: 字串切片的終止值,**包含final,而且也可以用喔** > [!Note] `string.gmatch` 類似 Python 的 rsplit ```lua= string.gmatch(str, pattern) -- 也可以寫成這樣 str:gmatch(pattern) ``` - `pattern`: 這是 Lua 自定義的字串規則 :::spoiler **pattern 合集** ### 基礎字元 | Pattern | 說明 | 範例 | 結果示意 | | ---------- | --------------------- | --------------------------- | ----- | | `.` | 任意一個字元(不包含換行) | `string.gmatch("abc", ".")` | a、b、c | | `%a` | 英文字母(A-Z, a-z) | `gmatch("a1B", "%a")` | a、B | | `%d` | 數字(0-9) | `gmatch("a1b2", "%d")` | 1、2 | | `%l` | 小寫英文字 | `gmatch("aB", "%l")` | a | | `%u` | 大寫英文字 | `gmatch("aB", "%u")` | B | | `%w` | 英文+數字(alphanumeric) | `gmatch("a1!", "%w")` | a、1 | | `%s` | 空白字元(空格、tab、換行等) | `gmatch("a b", "%s")` | 空格 | | `%p` | 標點符號(!, ., ?, etc.) | `gmatch("Hi!", "%p")` | ! | | `%c` | 控制字元(如換行、tab) | `gmatch("a\n", "%c")` | `\n` | | `%x` | 十六進位字元(0-9, a-f, A-F) | `gmatch("1aF", "%x")` | 1、a、F | | `%z` | 空字元(null byte) | 幾乎用不到 | | | `%` + 任意符號 | 將該符號轉義為字元(例如 `%.`) | `gmatch("3.14", "%.")` | . | ### 數量限定符(用在字元後面) | 修飾符 | 說明 | 範例 | 結果示意 | | --- | ---------- | ------------------------- | ---------- | | `+` | 一個以上 | `gmatch("123abc", "%a+")` | abc | | `*` | 0 個以上 (越多越好) | `gmatch("123", "%a*")` | ""(空字串,多次) | | `-` | 0個以上 (越少越好)| `gmatch("abc1xy", "%a-")` | abc(但盡量少抓) | | `?` | 0 或 1 個 | `gmatch("abc", "a.?")` | a、b、c | ### 群組與邊界 | Pattern | 說明 | 範例 | 結果示意 | | -------- | ---------------- | --------------------------- | ---------- | | `(...)` | 捕捉群組(會當作匹配結果) | `gmatch("a1b2", "%a(%d)")` | 1、2(只捕捉數字) | | `[^...]` | 除了括號中的字元以外 | `gmatch("abc", "[^a]")` | b、c | | `%bxy` | 平衡的配對括號(x 開 y 結) | `gmatch("(a(b)c)", "%b()")` | (a(b)c) | ### 字元集 | Pattern | 說明 | 範例 | 結果示意 | | ------- | ------------ | ------------------------ | ------ | | `[abc]` | a 或 b 或 c | `gmatch("abc", "[ab]")` | a、b | | `[a-z]` | 小寫英文字母範圍 | `gmatch("abc", "[a-c]")` | a、b、c | | `[0-9]` | 數字範圍 | `gmatch("123", "[0-9]")` | 1、2、3 | | `[%w_]` | 包含特殊符號需加 `%` | `gmatch("a_b", "[%w_]")` | a、\_、b | ::: :::success > [!Tip]while 先寫終止條件 ```lua= while condition do -- code end ``` **example** ```lua= i = 1 while i ~= 5 do print(i) i = i + 1 end ``` - `~=`: 不等於,其他語言通常是`!=` > [!Caution] 沒有像其他語言一樣有`i += 1`這種語法喔 ::: :::success >[!Tip] do-while 後寫終止條件 >類似 Python `while True` ```lua= repeat -- code (include end condition until ``` **example** ```lua= i = 1 repeat if i == 5 then break end print(i); i += 1 until ``` ::: ## function 把某段程式碼包起來 (chuck),並命名,可以讓他重複執行,同時也是物件導向的基礎喔 > JavaScript 的改造版 ```lua= function f(parameters) -- code return values end ``` - `parameters`: 函數中的參數,所有想得到資料型態都可以放喔 - `values`: 函數中得參數,所有想得到的資料型態都可以放喔 就是這麼的簡單,把JS的`{}`換成 end **example** ```lua= function add(a, b) return a + b end add(1, 2) --> 3 ``` ### 語法糖 > [!Tip] 1. 不定參數 就是想要寫個函式但不知道會有幾個參數 > Python 直接用list包起來就好了 ```lua= function group(...) local member = {...} -- 只能獲取值一次喔 s = 'Programming language prefix from A to E: ' for i=1, #member do if i ~= 1 then s = s .. ', ' end s = s .. member[i] end return s end str = group("Assembly", "basic", "C", "D", "E") print(str) --> Programming language prefix from A to E: Assembly, basic, C, D, E ``` > [!Tip] 2. 利用`table`當作函式參數 > `table` 之後會講 ```lua= function member(data) print (data.name .. " height: " .. data.height .. ", weight: " .. data.weight) end member { name = "Bob", height = "70", weight = "170" } ``` 3. lambda > 很多語言都有,來讓我回憶回憶寫法 :::spoiler 不同語言的 lambda > 我只會些部份而已,其他的玩過或是用查的 - **C++** ```cpp= auto add = [](int a, int b){return a + b;}; std::function<int(int, int)> add = [](int a, int b) -> int {return a + b;}; ``` - **C#** ```csharp= Func<int, int, int> add = (a, b) -> a+b; ``` - **Go** ```go= add := func(a int, b int) int {return a+b} ``` - **JavaScript** ```javascript= const add = (a, b) => a+b; ``` - **lisp** ```lisp= (defvar add (lambda (a b) (+ a b))) ``` - **perl** ```perl= my $add = sub { my ($a, $b) = @_; return $a + $b; }; ``` - **php (7.4+)** ```php= $add = fn($a, $b) => $a + $b; ``` - **Python** ```python= add = lambda a, b: a+b ``` - **Ruby** ```ruby= add -> (a, b) {a+b} ``` - **Rust** ```rust= let add = |a, b| a+b; ``` - **Swift** ```swift= let add = {(a: Int, b: Int) in a+b} ``` - **TypeScript** ```typescript= const add = (a: number, b: number): number => a + b; ``` ::: 正式開始吧,Lua 中的 lambda 很簡單,就是把函式當一行寫而已 ```lua= local add = function(a, b) return a+b end ``` 這裡都是基礎喔 都會的話就可以進到下一篇摟 [Lua2: table1 - 基礎的 table & metatable 操作](/pDEMlxKrRwajpJY-HtcYvA)