本博客采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本博客文章必须也遵循 署名-非商业用途-保持一致 的创作共用协议.
工作需要用到Lua做一些脚本, 所以学习一下这个在游戏开发应用广泛的语言, 当然, 我更喜欢称之为撸啊撸语言…
Lua
是一种轻量语言,它的官方版本只包括一个精简的核心和最基本的库, Lua
是一个动态弱类型语言, 支持增量式垃圾收集策略, 支持 协程
-- 命令行中输入lua, 使用REPL andrew_liu:Lua/ $ lua Lua 5.2.4 Copyright (C) 1994-2015 Lua.org, PUC-Rio > print "hello world"-- 国际编程学习惯例 hello world > print("hello world") hello world >
已经懒得再安利 brew
了(不好用你干我), 一行命令完成安装
# 安装路径为/usr/local/Cellar/lua $ brew install lua
单行注释使用 --
, 多行注释使用 --[[
和 --]]
-- 这种为单行注释 -- Date: 16/8/27 -- Time: 22:33 --[[ 这里是多行注释 --]]
local关键字
(是不是很变态) python
中的字符串表示形式 未定义的变量
不会报错, 而是返回nil(类似于C/C++中的NULL) -- variable age = 0-- 全局变量 sum = 2-- 所有数字都是double型 str = '蛤丝'-- 字符串可以是单引号和双引号 str1 = "还是蛤丝" -- 使用`[[]]`定义多行字符串时, 其空格都会被保留 str2 = [[多行的字符串 以两个方括号 开始和结尾。]] sum = nil-- 撤销sum的定义 test = not_define print(test) name, age, sex = "andrew",18,"male","蛤丝"-- 最后一个变量会被丢弃, 而不会报错(闷死发大财才是最吼得)
if-else与python有些像, 不过需要注意if和elseif最后的 then
和末尾的 end
-- if-else age = 100 ifage <=40andage >=20then print("young man!") elseifage >40andage <100then print("old man") elseifage <20then print("too young") else print("monster") end
Lua
同样支持三种循环, while循环, for循环, until循环(可以理解为C/C++中的do-while循环) 当条件满足, 会一直执行循环体
-- while num=0 whilenum<10do print(num) num=num+1 end
-- for sum=0 -- 1表示从1开始, 10表示最大为10(包含10) -- C++: for (int i = 1, i <= 10, ++i) fori =1,100do-- 包含1和100 sum=sum+ i end -- 类似于Python中的range操作, 2表示, 每次循环后i执行+2操作 -- C++: for (int i = 1, i <= 10, i = i + 2) fori =1,10,2do-- 1,3,5,7,9 print(i) sum=sum+ i end -- ..操作符用于连接字符串, 可以理解为python中字符串的+ 操作 print("sum = "..sum)
until循环, 类似于C/C++中的do-while语句
-- until(do-while) sum=2 -- 中文: 直到sum的值大于1000时, 才终止循环 repeat sum=sum^2-- 幂操作 untilsum>1000 print("do-while, sum = "..sum)
local
, 和局部变量类似 -- function(return支持返回多个值), 函数是一等公民 functionadd(a,b) returna+ b end print("1 + 2 = "..add(1,2)) -- 匿名函数 f = function(a,b) returna* b end print ("匿名函数: ".. f(2,3))
functionfib(n) ifn <2thenreturnnend returnfib(n -2) + fib(n -1) end
Table
是Lua中核心数据结构, 我理解为其他语言中的 Dict/Map
数据结构(key-value的数据结构), 而数组等在Lua中都是通过 Table
来表示的
Table可以使用任何非nil的值作为key
--Lua唯一的组合数据结构 -- 可以使用任何非nil值作为key --Table(key-value数据结构) map = { name = "andrew", -- 此处name默认使用字符串作为key age = 18, sex = "male" } -- 上下两种写法等价 --map = {['name'] ='andrew', ['age'] =18, ['sex'] ='male'}
对Table创建, 读取, 更新和删除操作, key-value的读取可以通过 .
符号
-- Table的CRUD map['hobby'] ="膜蛤"--map.hobby ="膜蛤" print(map.name) map.age =19 map.sex =nil -- 删除key
遍历一个Table
-- 遍历一个Table fork, vinpairs(map)do print(k, v) end
Lua
中数组的下标是从1开始, 从1开始, 从1开始. 重要的事情说三遍.
-- array, 数组下标从1开始 -- 数组中可以是不同类型的数据 arr = {"string",100,"andrew",function()print("hello world")end} -- 等价于 -- arr = {[1]="string", [2]=100, [3]="andrew", [4]=40, [5]=function()print("hello world")end} fori =1,#arr do -- #arr表示数组的长度 print(arr[i]) end
Table的 metatable
提供一种类似于操作符重载的机制, 写个python的可能重写个 __add__
方法, 感觉有点类似
setmetatable
将自己实现的metamethod绑定到对应的Table对象中 -- table的元表提供一种机制,支持操作符重载 data_one = {a=1, b =2}-- data_one和data_two 可以看做表示1/2和3/4 data_two = {a=3, b =4} meta_fraction = {} -- 新定义一个元表 functionmeta_fraction.__add(f1,f2) --__add是build-in的原方法 localsum= {} sum.b = f1.b * f2.b sum.a= f1.a* f2.b + f2.a* f1.b returnsum end setmetatable(data_one, meta_fraction) -- 为之前定义的两个table设置metatable setmetatable(data_two, meta_fraction) s = data_one + data_two -- 执行 + 操作
__index
可以重载用于查找的点操作符, 我理解有点类似于python中的 __getattr__
, 对类中的属性做查找 -- 当表要索引一个值时如table[key], Lua会首先在table本身中查找key的值, -- 如果没有并且这个table存在一个带有__index属性的Metatable, 则Lua会按照__index所定义的函数逻辑查找 default_map = {name = 'andrew', sex ='male'} new_map = {age = 18} setmetatable(default_map, {__index = new_map}) print(default_map.name, default_map.age)-- 继承了new_map的属性
__add
这种方法在Lua中被称为元方法,
-- __add(a, b)fora + b -- __sub(a, b)fora - b -- __mul(a, b)fora * b -- __div(a, b)fora / b -- __mod(a, b)fora % b -- __pow(a, b)fora ^ b -- __unm(a)for-a -- __concat(a, b)fora .. b -- __len(a)for#a -- __eq(a, b)fora == b -- __lt(a, b)fora < b -- __le(a, b)fora <= b -- __index(a, b) <fn or a table>for a.b -- __newindex(a, b, c)fora.b = c -- __call(a, ...)fora(...)
继承
同样是通过元表和元方法来实现的.
-- table实现继承 Dog = {} -- 这个new函数我理解为继承类的构造函数, 冒号(:)函数会使参数默认增加一个self作为参数 functionDog:new() -- 下面这句相当于继承的类增加的新的成员变量 localnew_obj = {sound ='woof'} self.__index = self returnsetmetatable(new_obj, self) end functionDog:make_sound()-- 等价于Dog.make_sound(Dog) print("say ".. self.sound) end -- 使用 new_dog = Dog:new() -- new_dog获得Dog的方法和变量列表 new_dog:make_sound()
self.__index = self
是防止self被扩展后改写,所以,让其保持原样 setmetatable(new_obj, self)
会返回第一个参数, new_obj会得到self的函数 Dog:new()
调用方式会增加一个隐式参数 self
--module --1.require local test = require('module') -- require文件会被缓存 -- test.say_my_name() -- 不能调用local test.say_hello() --2. dofile 类似require但不缓存 --3. loadfile加载一个lua文件, 但是并不运行它