继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

简单入门Lua编程语言

scq000
关注TA
已关注
手记 22
粉丝 14
获赞 130

最近在学习写Kong的插件,作为新手,首先要学习的就是它所使用的编程语言lua,这个语言主要应用在nginx的开发中,Kong作为一个API网关系统,有时候需要写一些自定义的插件,所以会涉及到lua语言。这篇文章主要记录学习过程中的一些经验,希望对大家的学习有帮助。

Install 安装

学习的第一步,肯定是安装对应的开发环境。Lua的开发环境,在不同的操作系统上有不同的安装方法,比较简单的是在MAC上一条命令就搞定了。

brew install lua

Windows就下载对应的二进制安装包进行安装就好了。

Hello World

安装完环境后,我们来写一个hello world的程序,来测试一下环境是否正常。

新建一个helloworld.lua的文件:

print("Hello World")

在命令行中输入:

lua helloworld.lua

看到输出熟悉的hello world,就证明一切正常。

Comment注释

下来就是语言的基本语法,先学习一下注释的使用。lua语言当中采用的是–作为注释标示符,就像这样:

--- comment

变量声明

作为弱类型语言,在声明变量的时候,我们可以不必去指定它的数据类型。

来看个简单的例子:

name = "scq000"

io.write("Length of name", #name, "\n")

age = 4

io.write("My age is ", age, "\n")

使用io.write函数直接输出对应的变量名等,其中#作为运算符可以获取字符串的长度。

如果要生成一个长字符串,可以使用下面这种写法:

longString = [[
  I am a very long long string that 
  dfsfdsfsdfs
]]
io.write(longString, "\n")

longString = longString .. name
-- 连接操作
io.write(longString, "\n")

数据类型的话,lua语言当中只支持浮点数:

bigNum = 9234324342342 + 1
io.write("Big Number" , type(bigNum), "\n)

floatPrecision = 1.99999999999999 + 0.0000000000000005
floatPrecision = 1.99999999999999 + 0.00000000000000055

获取变量类型信息

我们可以使用type函数来获取变量的基本类型:

isWrite = true
io.write(type(isWrite))

Math Function

和其他语言类似,在lua语言内部包含了很多内置的数学函数可以直接调用。

io.write("5 + 3 = ", "\n")
io.write("5 * 3 = ")

-- number
-- floor ceil max min, sin, cos, sqrt

math.floor(134.33223)
math.random()
math.random(10)
math.random(5, 100)

math.randomseed(os.time())

print(string.format("Pi = %.10f", math.pi))

关系运算符和逻辑运算符

关系运算符和其他语言大同小异,逻辑运算符采用的是单词形式 and or not,简单的例子如下:

-- Relational Operators: > < >= <= == ~=
age = 13
if age < 16 then
  io.write("You can go to school", "\n")
  local localVar = 10
elseif (age <= 16) and (age < 18) then
  io.write("You can drive", "\n")
else
  io.write("You can vote", "\n")
end

-- Logical Operators: and or not

toString(not true)
canVote = age > 18 ? true : false

canvote = age > 18 and true or false

lua语言中的代码分块采用end进行结尾,和其它语言中使用{}进行分块不太一样。

字符串操作

以下是常用的字符串操作:

-- get length
string.len(quote)
-- or
#quote

-- replace string
string.gsub(quote, "I", "me")

-- find and get index
string.find(quote, "password")

-- upper /lower
string.upper(quote)
string.lower(quote)

循环,分支控制语句

lua中支持的循环语句类型比较多:

  1. while循环:
i = 1

while (i <= 10) do
  io.write(i)
  i = i + 1
  
  if i == 8 then break end
end
  1. until循环: 和其它语言中do…until类似,这里采用的是repeat…until的语法。
repeat
  io.write("enter your guess:")
  
  guess = io.read()
  
until tonumber(guess) == 15
  1. for循环: 循环体的写法不需要用括号进行分隔,采用for…do的语法。
for i = 1, 10, 1 do
  io.write(i)
end

months = {"Juanary", "February", "March", "April"}

for key, value in pairs(months) do
  io.write(value, " ")
end

Table

在lua语言中,支持一种table的抽象数据结构,可以用来存储键值对对象。

aTable = {}

for i = 1, 10 do
  aTable[i] = i
end

io.write("First : ", aTable[1])

io.write("Number of Items: ", #aTable, "\n")

table.insert(aTable, 1, 0)

io.write("First : ", aTable[1])

-- remove
table.remove(aTable, 1)

-- convert to string
print(table.concat(aTable, ", "))

二维表结构的定义与上面的例子差不多:

aMultiTable = {}

for i = 0, 9 do
  aMultiTable[i] = {}
  for j = 0, 9 do
    aMultiTable[i][j] = tostring(i) .. tostring(j)
  end
  print()
end

io.write("Table[0][0] : ", aMultiTable[0][0], "\n")

functions

函数是进行语言抽象化必备的工具,所以在lua语言中,直接使用function来定义对应的函数就可以了:

function getSum(num1, num2)
  return num1 + num2
end

print(string.format(" 2 + 6= %d", getSum(2,6)

下面这里例子演示了如何一个实现分割字符串功能的函数:

function splitStr(theString)
  stringTable = {}
  
  local i = 1
  
  for str in string.gmatch(theString, "[^%s]+") do
    stringTable[i] = str
    i + i + 1
  end
 
  return stringTable, i
end

splitStrTable, numOfStr = splitStr("The Turtle")

for j = 1, numOfStr do
  print(string.format("%d : %s", j splitStrTable[j]))
end

这里需要注意在函数内部声明局部变量要使用local关键字,以确定变量的作用域。

function的参数支持不定长参数,使用...语法就可以了:

function getSumMore(...)
  local sum = 0
  
  for k, v in pairs{...} do
    sum = sum + v
  end
  return sum
end

io.write("Sum ", getSomeMore(1,2,3,4,5,6), "\n")

闭包这个结构在函数式编程语言中算是比较常见的,内部函数可以访问它上层所定义的局部变量。

doubleIt = function(x) return x * 2 end

print(doubleIt(4))

--- 输出 8

function outerFunc()
  local i = 0
  
  return function()
    i = i + 1
    return i
  end
end

getI = outerFunc()

print(getI())

-- 输出 1

coroutine 协程

协程是跟线程类似的概念,但在粒度上比线程要小,主要是在其自身上下文中进行切换。而且各个协程需要进行协作才能很好地工作。一个程序在同一时间只能运行一个协程,而且协程要显示挂起才能不强占资源。

主要的方法有create, resume, yield, running, status等,分别用来进行创建、恢复、传参、返回正在运行的协程和返回协程状态等操作。

co = coroutine.create(function()
	for i = 1, 10, 1 do
      print(i)
      print(coroutine.status(co))
      if i == 5 then coroutine.yield() end
      end
    end
)

print(coroutine.status(co))

coroutine.resume(co)

print(coroutine.status(co))

运行结果如下:

> print(coroutine.status(co))
suspended
>
> coroutine.resume(co)
1
running
2
running
3
running
4
running
5
running
true
>
> print(coroutine.status(co))
suspended

file文件操作

文件操作主要利用io这个接口中。常用的语法和c语言等都很类似,运行一个实例方法用采用:这种语法:

-- r
-- w
-- a: Append
-- r+: read & write existing file
-- w+: overwrite read or create a file
-- a+: append read or create file

file = io.open("test.lua", "w+")

file:write("Random String of text\n")
file:write("Some more text\n")

file:seek("set", 0)

print(file:read("*a"))

file:close()

file = io.open("test.lua", "a+")

file:write("Even more text\n")
file:seek("set", 0)

print(file:read("*a))

file:close()

Modules

在进行大工程化开发,模块化是必须的,所以我们直接在一个文件中声明一个模块,并将这个模块导出:

新建一个covert.lua的文件:

-- covert.lua

local convert = {}

function convert.ftToCm(feet)
  return feet + 30.48
end

return convert

在另一个入口文件index.lua中,使用require语法进行引用:

convertModule = require("convert")

print(string.format("%.3f cm", convertModule.ftToCm(12)))

在命令行中运行lua index.lua后结果显示:

42.480 cm

MetaTable

lua中有一种数据类型是元表,和哈希表类似,通常可以把它看做是一个备用查找表。在Lua中在一个表中查找元素,如果没有找到,会去其关联的元表中继续进行查找。

使用setmetatable方法可以给一个表对象新增一个元表。我们还可以自己去定义元表的操作方法:

aTable = {}

for x = 1, 10 do
  aTable[x] = x
end

--     _sub _mul _div _mod _concat
mt = {
 __add = function(table1, table2)
    sumTable = {}
    
    for y = 1, #table1 do
      if(table1[y] ~= nil) and (table2[y] ~= nil) then
        sumTable[y] = table1[y] + table2[y]
      else
        sumTable[y] = 0
      end
    end
    
    return sumTable
 end,
  
  __eq = function(table1 table2)
    return table1.value = table2.value
  end
}

setmetatable(aTable, mt)

print(aTable == aTable)

--- print true

Class OOP 面向对象

lua也支持面向对象的语言机制,在新建一个对象的时候,会调用其new方法

Animal = {height = 0, weight = 0, name = "No Name", sound = "No Sound"}

function Animal:new (height, weight, name, sound)
  setmetatable({}, Animal)
  
  self.height = height
  self.weight = weight
  self.name = name
  self.sound = sound
 
  return self
end

function Animal:toString()
  animalStr = string.format("%s weighs %.1f lbs, is %.1f in tall and says %s", self.name, self.height, self.weight, self.sound)
  return animalStr
end

spot = Animal:new(10, 15, "Spot", "woof")

print(spot:toString())

--- print Spot weighs 10.0 lbs, is 15.0 in tall and says woof

总结

大多数的lua语言都和其它的现代编程语言大同小异,如果你已经有了其它的语言的基础,在学习的时候多对比,多总结,可以加速你掌握的速度。熟悉了大致的语言语法之后就可以投入实践中,多写一些demo,就能熟能生巧了。

参考资料

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP