# 簡介 & 安裝
## 介紹 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)