記事ディレクトリ
(これはチュートリアルではありません。基本的なプログラミングの知識がある人がこの記事を読むことをお勧めします)
この記事では主に初心者向けのチュートリアルからの学習と理解について説明しますが、個人的には Lua 言語と Python は多くの点で似ていると感じています。
以下のコードと表の大部分は、初心者向けチュートリアルからの抜粋です。
function start()
Lua 変数
データの種類
データの種類 | 説明する |
---|---|
なし | このクラスには値 nil のみが属し、無効な値 (条件式の false に相当) を表します (Null または None と同様) |
ブール値 | 偽りと真 |
番号 | 倍精度浮動小数点数 |
弦 | 文字列は二重引用符または一重引用符のペアで表されます |
関数 | C または Lua で書かれた関数 |
ユーザーデータ | 変数に格納された任意の C データ構造を表します。 |
糸 | コルーチンの実行に使用される独立した実行行を表します (では、なぜそれをスレッドと呼ぶのでしょうか?) |
テーブル | Lua のテーブルは実際には「連想配列」であり、配列のインデックスは数値、文字列、またはテーブル型になります。Lua では、テーブルの作成は「構成式」によって行われます。最も単純な構成式は、空のテーブルを作成するために使用される {} です。 |
変数宣言
a = 5 -- 全局变量
local b = 5 -- 局部变量
Lua では、local を使用して変数をローカル変数として明示的に宣言します。宣言されていないものはすべてグローバル変数です。
a -- nil
a = 5 -- number
a = false -- bool
a = "" -- string,单双引号都可以,支持转义字符,print出空字符串而非nil
在lua中字符串尾部没有\0,而且\0即使在字符串中也不代表结束且不计入长度
我们也可以用16进制来定义字符串
s = string.char(0x30,0x31)
n = string.byte(s,2) --转为Ascii码,第一个字符是从1开始的而非0
print(s,n) --结果: 01 49
a,b,c = 1,"a" -- 多重赋值
print(a, b, c) -- 1 a nil
a = nil -- nil,回收变量
local multilineString = [[
This is a multiline string.
It can contain multiple lines of text.
No need for escape characters.
]]
print(multilineString) -- 按格式输出括号内字符
This is a multiline string.
It can contain multiple lines of text.
No need for escape characters.
整数型が定義されているか浮動小数点型が定義されているかに関係なく、Lua では常に数値になります。値が割り当てられていない変数は nil です。興味深いことに、空の文字列が代入されていても文字列型であることに変わりはなく、Lua の nil は C と同様、つまりベース アドレスが割り当てられていないことを意味するようです。
Lua は複数の変数に同時に値を割り当て、変数を転送せず、値のみを転送します。
a, b = 0, 1
a, b = a+1, a+1
print(a,b); --> 1 1而非1 2
ちなみに、Lua ステートメントの末尾にセミコロンを付けることもできます。
その他の表現
a = 0x11 -- 16进制表示,16+1=17
b = 2e10 -- 科学计数法,2*(10^10)
c = 5^2 -- 乘方,25
d = 5%2 -- 取余(mod),1
e = 5//2 -- 整除运算,2 (>=lua5.3)
f = 1<<3 -- 移位符号(>=lua5.3),二进制表示下移位:1 = 00000001左移三位(000)00001000 = 8
a,b = "abc","def"
c= a..b --字符串连接,"abcdef"
print(#c) --#输出变量长度(可以是字符串或者表),6
-- 其他语法例如tostring(number),tonumber(string)都是很常规的
n = tonumber("a") --nil,需要注意的是lua和cpp不同,单个字符也不会转为ASCII码
Lua の構文
判断
論理的判断 (Lua は非常に特殊なので、こちらの方が重要です)
Lua は false と nil を false、true と非 nil を true とみなします。したがって、0 はそれも true であることを意味します。
注意すべき唯一のことは、Lua における不等式はそれぞれ~=
と および or notであるということです
。次の例を見てみましょう:
a = nil -- false
b = 0 -- true
print(a and b)
print(a or b)
print(not a)
nil
0
true
Lua における従来の論理判定では True または False が返されず、not 判定の場合のみ True と False が返され、and と or では論理値に対応する変数の値のみが返されることがわかります。
よりわかりやすくするために別の例を示します
(たとえば、a=nil、値は false に対応するため、a と b は nil を返します。また、値 b=0 は True に対応し、a または b は 0 を返します)。
a = nil -- false
d = false -- false
B = 0 -- true
C = 1 -- true
and时一真一假输出结果是false的一方
print(a and C) --逻辑判断值返回了逻辑符号左右值中的对应真值和假值
print(C and d)
or时一真一假输出结果是true的一方
print(a or C)
print(C or d)
结果:
nil
false
1
1
上述例子是正常计算都可以得出的,现在让我们看几个特殊例子
以下例子请抛弃依次执行语句的程序思维,使用更逻辑化,更符合计算机的思维来判断
a = nil -- false
d = false -- false
B = 0 -- true
C = 1 -- true
and时两侧都是真值,则返回右侧的值
print(B and C)
print(C and B)
and时两侧都是假值,则返回左侧的值
print(a and d)
print(d and a)
结果:
1
0
nil
false
or时两侧都是真值,则返回左侧的值
print(B or C)
print(C or B)
or时两侧都是真值,则返回右侧的值
print(d or a)
print(a or d)
结果:
0
1
nil
false
どうしてこれなの?おそらくプログラム的な観点から見ると、ステートメントを実行してから判断する必要があります。ただし、論理ゲートの判定を実装するには、論理記号と値の 1 つだけが必要な場合があります。
接下来用T代表真,F代表假,?代表任意bool
print(F and ?)
在进行and运算的时候,如果第一个值就为false,那输出值一定为false,?是什么都不影响了,所以结果一定为false,输出F即可
print(T and ?)
在进行and运算的时候,如果第一个值为true,我们依然无法确定输出值,此时我们需要知道?是true还是false
但是最后的运算结果一定是由?决定的,如果?为true运算就是true,问号为false运算就是false,所以and左值为真时,输出的结果一定是右值
因此该语句会输出 ?
print(T or ?)
同理,or运算中如果左值为true,结果一定为true,因此输出T即可
print(F or ?)
or运算中如果左值为false,最后结果则是由?是true还是false决定,因此输出结果一定是右值
上述语句输出 ?
现在再回头看看刚才的例子,是不是能理解了?
短絡判定
基于上述的原理我们可以进行短路判断
a = nil -- false
b = 0 -- true
print(b > 10 and "yes" or "no")
输出:
no
所以所谓短路判断,前面应当是正常的判断语句,最后加上and A or B,其中AB都是true值
【T and A or B = A, F and A or B =B】
当前面为真则输出A,当前面为假则输出B
もし
if(0)
then
print("0 为 true")
end
そうでなければ
a = 100;
if( a < 20 )
then
print("a 小于 20" )
else
print("a 大于 20" )
end
print("a 的值为 :", a) --a 大于 20
--a 的值为 : 100
サイクル
その間
Break キーワードは普遍的です
while( a < 20 )
do
a = a+1
end
のために
for i=1,10,2 do --- 三个值依次代表起始,结束,步长,步长不输入默认为1
print(i)
end
繰り返す
a = 10
repeat -- 不同与while for,repeat在循环结束时判断,类似do while
print("a的值为:", a) --输出10,11,12,13,14,15
a = a + 1
until( a > 15 ) --当a=16时退出
最も重要な知識点は、if、while、for、function に end を忘れずに追加することです。
イテレータ
イテレータのジェネリック
イテレータは、C# の each や Python の in に似ています。
array = {
"Google", "Runoob"}
for key,value in ipairs(array) -- key,value自定义常量名,ipairs(array)迭代列表
do
print(key, value)
end
1 Google
2 Runoob
ステートレス反復子
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
--定义了一个方法square实现循环三次后结束
for i,n in square,3,0 --square,3,0代表了迭代方法和它的两个入参,当方法结束主动闭包
do
print(i,n)
end
1 1
2 4
3 9
複数状態イテレータ
反復関数が多くの情報を受け取る必要がある場合、反復関数の入力パラメーターを簡素化するために、すべてのステータス情報をテーブルにカプセル化し、そのテーブルを反復子のステータス定数として使用することもできます。この場合、すべての情報を table に保存できるため、通常、反復関数には 2 番目のパラメーターは必要ありません。
array = {
"Google", "Runoob"}
function elementIterator (collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Google
Runoob
注: どのような関数が定義されているかに関係なく、最終的に反復子の対応する値を出力するには、関数を反復変数に返す必要があります。
Lua関数
ワンステップで正しく実行するためのいくつかの簡単な例
----------------------
function f() --同样未用local声明,该函数为全局函数
a,b=1,2 -- 函数内定义没有local声明也是全局变量
print(a,b)
end
f() -- 1 2
--------------------
local function f(a,b,n) --local声明后为局部函数
c, d = a, b
print(c, d,n)
end
f(1,2) -- 1 2 nil
-------多返回值--------------------
function f(a,b,c)
return a,b,c
end
local i,j =f(1,2)
print(i,j) -- 1 2
--------可变参数---------------
function average(...) --使用...可以接收任意多参数
result = 0
local arg={
...} --> arg 为一个table,局部变量
for i,v in ipairs(arg) do
result = result + v
end
print("总共传入 " .. #arg .. " 个数")
print("总共传入 " .. select("#",...) .. " 个数") --select("#",...)来获取可变参数的数量,和直接#arg功能是一样的
return result/#arg
end
print("平均值为",average(10,5,3,4,5,6))
---总共传入 6 个数
---总共传入 6 个数
---平均值为 5.5
-----------
function average(a,...) --也可以用固定参数+可变参数,但是固定参数一定放在可变参数之前
end
------------------------
メソッドの選択
通常、可変長パラメータを走査するときは、{...} を使用するだけで済みます。ただし、可変長パラメータには nil が含まれる場合があるため、select 関数を使用して可変長パラメータにアクセスできます: select('# ', ...) または select(n ,...)
select('#', …) は変数パラメータの長さを返します。
select(n, …) は、開始点 n から終了位置までのすべてのパラメータのリストを返すために使用されます。
select を呼び出すときは、固定引数セレクター (セレクター スイッチ) と一連の可変長パラメーターを渡す必要があります。selector が数値 n の場合、select はインデックス n から終了位置までのパラメータ リスト内のすべてのパラメータのリストを返します。それ以外の場合は文字列 # のみであるため、select は可変長パラメータの合計数を返します。
function cal_sum(...)
a,b =select(3,...)
print(select(3, ...))
print(select("#",...) )
end
cal_sum(1,2,3,nil,5,5)
print(a,b)
3 nil 5 5
6
3 nil
使用select赋值会对变量顺序赋值,而select本身可以获取序号及其后的所有可变参数
配列
Lua には従来の意味での単一タイプのデータ構造はなく、すべての値を順番に格納し、アクセスのためのインデックスを提供できるテーブル構造のみがあります。
インデックスは従来の 0 ではなく1から始まることに注意してください。
function P ()
return 1;
end
a={
1,"ac",{
},function() end,P}
print(a[3])
print(a[4])
print(a[5])
print(#a)
a[6] = 1223;
print(a[6])
print(#a)
结果:
table: 00BCA580
function: 00BCCAC8
function: 00BCCC48
5
1223
6
上記のテーブルには、数値、文字列、テーブル、さらには 2 つの関数を含む、多くの奇妙な値が格納されていることがわかりました。
出力結果から、一般的な変数タイプの場合、テーブル インデックスが値を直接返すことができることがわかります。テーブル関数などの特殊な型の場合は、ストレージ型 + ストレージアドレスが返されます。
-- insert用法,没有返回值
table.insert(a, "d") --插入到尾部
print(a[7])
s = table.insert(a, 2, 233) --插入到位置2,其后的元素都会后移一位
print(s)
print(a[2])
d
nil
233
-- remove会有返回值
s = table.remove(a, 1)
print(s)
print(a[1])
1
ac
文字インデックス
テーブルには文字によってインデックスを付けることができます。
a = {
a = 1,
b = "1234",
c = function()
end,
d=123456,
["!?"] =123
}
a["abc"]="abc"
print(a["a"])
print(a.a)
print(a["!?"]) -- 这只是个例子,别用奇怪的符号命名
-- print(a.!?) --打印不了的,符号会报错
print(a.abc)
print(a.def) --没有这个下标
1
1
123
abc
nil
テーブルが実際にキーと値のペアの形式で格納されていることを見つけるのは難しくありません。
_G
_G は、すべてのグローバル変数を保存するグローバル テーブルです。これを通じて任意のグローバル変数にアクセスできます。
a = 1
b = 2
print(_G["a"])
print(_G.b)
1
2
上記のことがまだ理解できるとしても、次の特徴は単純に奇妙です。
之前我们往tableA里不是使用table.insert插入了一个值吗?让我们看看怎么实现的
table.insert(table, 1, "aa")
- lua内有一个全局变量,它的名字就叫table,它的类型是table
- 我们可以直接使用table.insert的原因其实是直接访问了这个名称为table的table的一个字符串索引
- 这个字符串索引的名称是"insert",这个索引对应的值是一个function
- 这个函数实现了往指定table的指定位置插入指定值的功能
print(table[1])
print(_G["table"]["insert"])
输出:
aa
function: 00CE8B48
結論:忘れないでください
end