Lua Basic

本文主要参考自官方文档中的 Basic Concepts 一章.

Lua 中一共有这么 8 种基本数据类型:

  • nil: 类似于 None

  • boolean: true 和 false

  • number: 整数和浮点都是这个

  • string

  • function: 函数也是一个数据类型

  • userdata

  • thread

  • table: 万能数据结构, 即是列表, 也是字典, 还是面向对象的类

#!/usr/bin/env lua

a = 2
b = 6
c = 9

print(string.format("a = %s", a))
print(string.format("b = %s", a))
print(string.format("c = %s", a))

print(string.format("a + b = %s", a + b))
print(string.format("a - b = %s", a + b))
print(string.format("a * b = %s", a * b))
print(string.format("a / b = %s", a / b))
print(string.format("b / a = %s", b / a))
print(string.format("c / a = %s", c / a))
# output
a = 2
b = 2
c = 2
a + b = 8
a * b = 12
a / b = 0.33333333333333
b / a = 3.0
c / a = 4.5

String

字符串拼接

#!/usr/bin/env lua

s = "a"
print(string.format("s = %s", s))
s = "b" .. s
print(string.format("s = %s", s))
s = "d" .. "c" .. s
print(string.format("s = %s", s))
s = "e"..s
print(string.format("s = %s", s))

两个点 .. 是字符串拼接. 相当于 Python 中的 s = "b" + s.

# output
s = a
s = ba
s = dcba
s = edcba

Function

在 Lua 中定义函数非常简单, 其中 function, return, end 是关键字.

function func_name(arg1, arg2)
    ...
    return result
end

定义函数

第一个例子, 函数里面可以有参数, Lua 是动态语言, 参数是没有类型的. 如果一个参数被定义了, 但是却没有被赋值, 那么它的默认值是 nil.

#!/usr/bin/env lua

function func(msg)
    print(string.format("msg = %s", msg))
    return "success"
end

res = func("hello alice")
print(string.format("res = %s", res))

func()
# output
msg = hello!
res = success
msg = nil

定义多个参数

#!/usr/bin/env lua

function func(msg1, msg2)
	print(string.format("msg1 = %s", msg1))
	print(string.format("msg2 = %s", msg2))
	return "success"
end

func("hello alice", "hello bob")
# output
msg1 = hello alice
msg2 = hello bob

定义多个参数

#!/usr/bin/env lua

function func(msg1, msg2)
	print(string.format("msg1 = %s", msg1))
	print(string.format("msg2 = %s", msg2))
	return "success"
end

func("hello alice", "hello bob")
# output
msg1 = hello alice
msg2 = hello bob

定义可变长度的参数

这里明确两个定义:

  • 形参 Formal parameter, 定义的形式参数, 可以是任何值

  • 实参 Actual parameter, 实际传入的参数, 是一个确定值

例如下面的 a 就是形参, 1 就是实参.

function func(a)
...
end

func(1)

下面的例子中我们用 ... 来表示该函数可以接受数量不同的实参. 当这个函数被调用时, 它的所有参数都会被收集到一起. 我们定义了个临时变量 args, 它是个 table, 然后我们就可以用 ipairs 函数遍历里面的元素了, 当然我们对 index 不感兴趣, 只对 value 该兴趣, 所以可以用 _ 语法 (和 Python 一样) 来忽略 index.

#!/usr/bin/env lua

-- Ref: https://www.runoob.com/lua/lua-functions.html

function func(...)
	local args = {...}
   	for _, arg in ipairs(args) do
		print(arg)
   	end
end

func("alice", "bob")
# output
alice
bob

定义 Key Value 风格的参数

在 Lua 中给函数传递参数都是 positioned, 也就是只按照位置顺序传递参数. 如果你记不住这些参数的位置, 想要用 key value 的方式调用函数, 那么你只能将函数变为只有一个参数的形式, 而且这个参数是一个 table, 然后在函数内部都用 arg.key 的形式调用这些值即可.

#!/usr/bin/env lua

function add_two(arg)
    return arg.a + arg.b
end

print(add_two({a=1, b=2}))

Table

Lua 中有且只有一个数据结构 Table. 它即是链表, 也是哈希表, 还能实现模块, 面向对象等功能.

Table as Dict

我们这里用 Python 中的 dict 来类比, 看看把 Table 当哈希表用是什么感觉.

#!/usr/bin/env lua

local t = {
    a = 1,
    b = 2,
}

print("--- access value from key ")
print(string.format("t[\"a\"] = %s", t["a"]))

print("--- iterate key value pair:")
for k, v in pairs(t) do
    print(string.format("key = %s, value = %s", k, v))
end

print("--- iterate key only pair:")
for k, _ in pairs(t) do
    print(string.format("key = %s", k))
end

print("--- iterate value only pair:")
for _, v in pairs(t) do
    print(string.format("value = %s", v))
end

print("--- check if table has certain key")
print(string.format("table has key \"b\": %s", t["b"] ~= nil))
print(string.format("table has key \"c\": %s", t["c"] ~= nil))

print("--- assign key value pair")
t["b"] = 20
t["c"] = 30
print(string.format("t[\"b\"] = %s, t[\"c\"] = %s", t["b"], t["c"]))

print("--- delete key value pair")
t["a"] = nil
for k, v in pairs(t) do
    print(string.format("key = %s, value = %s", k, v))
end

print("--- get number of pairs in table")
function get_table_length(t)
    local count = 0
    for _ in pairs(t) do
        count = count + 1
    end
    return count
end
print(string.format("%s", get_table_length(t)))
# output
--- access value from key
t["a"] = 1
--- iterate key value pair:
key = a, value = 1
key = b, value = 2
--- iterate key only pair:
key = a
key = b
--- iterate value only pair:
value = 1
value = 2
--- check if table has certain key
table has key "b": true
table has key "c": false
--- assign key value pair
t["b"] = 20, t["c"] = 30
key = c, value = 30
key = b, value = 20
❯ lua table_as_dict.lua
--- access value from key
t["a"] = 1
--- iterate key value pair:
key = b, value = 2
key = a, value = 1
--- iterate key only pair:
key = b
key = a
--- iterate value only pair:
value = 2
value = 1
--- check if table has certain key
table has key "b": true
table has key "c": false
--- assign key value pair
t["b"] = 20, t["c"] = 30
--- delete key value pair
key = b, value = 20
key = c, value = 30
--- get number of pairs in table
2

Table as List

我们这里用 Python 中的 list 来类比, 看看把 Table 当列表用是什么感觉.

#!/usr/bin/env lua

local t = {
    [1] = "a",
    [2] = "b",
    [3] = "c",
    [4] = "d",
    [5] = "e",
}

print("--- get element by index, lua index start from 1")
print(string.format("t[1] = %s", t[1]))
print(string.format("t[2] = %s", t[2]))

print("--- get the last item in the list")
print(t[#t])

print("--- get the second last item in the list")
print(t[#t - 1])

print("--- iterate a list")
for i, v in ipairs(t) do
    print(string.format("ind = %s, value = %s", i, v))
end

print("--- iterate the slice of the list")
for i, v in ipairs(t) do
    if 2 <= i and i <= 4 then
        print(string.format("ind = %s, value = %s", i, v))
    end
end

print("--- append to the end")
table.insert(t, "f")
print(t[6])

print("--- remove the last element end")
table.remove(t)
print(t[6])
print(t[5])
#output
--- get element by index, lua index start from 1
t[1] = a
t[2] = b
--- get the last item in the list
e
--- get the second last item in the list
d
--- iterate a list
ind = 1, value = a
ind = 2, value = b
ind = 3, value = c
ind = 4, value = d
ind = 5, value = e
--- iterate the slice of the list
ind = 2, value = b
ind = 3, value = c
ind = 4, value = d
--- append to the end
f
--- remove the last element end
nil
e

Local and Global Variable

在 lua 中, 如果你不声明 local 就定义变量, 那么这个变量就是全局变量. 全局变量可以在函数内部被修改. 一般好的 lua 代码中所有的变量都应该定义成局部变量才能避免出 bug. 请看下面的例子:

#!/usr/bin/env lua

a = 1
function func1()
    a = 2
    print(string.format("inside function a = %s", a))
end
func1()
print(string.format("outside function a = %s", a))


b = 1
function func2()
    local b = 2
    print(string.format("inside function b = %s", b))
end
func2()
print(string.format("outside function b = %s", b))


local c = 1
function func3()
    c = 2
    print(string.format("inside function c = %s", c))
end
func3()
print(string.format("outside function c = %s", c))


local d = 1
function func4()
    local d = 2
    print(string.format("inside function d = %s", d))
end
func4()
print(string.format("outside function d = %s", d))
# output
inside function a = 2
outside function a = 2
inside function b = 2
outside function b = 1
inside function c = 2
outside function c = 2
inside function d = 2
outside function d = 1

OOP

#!/usr/bin/env lua

local Rectangle = {
    width = 0,
    height = 0,
}

function Rectangle:new(arg)
    rect = {}
    setmetatable(rect, self)
    self.__index = self
    rect.width = arg.width or 0
    rect.height = arg.height or 0
    return rect
end

function Rectangle:area()
    return self.width * self.height
end

rect1 = Rectangle:new({width=3, height=4})
print(rect1.width)
print(rect1:area())

Reference: