Lua 流程控制

  • 控制结构的条件表达式结果可以是任何值,
    • false和nil为假,
    • true和非nil为真。
    • 0 为 true:
--[ 0 为 true ]
if(0)
then
    print("0 为 true")
end

a = 100;

if( a < 20 or nil)
then
   print("a 小于 20" )
else
   print("a 大于 20" )
end
print("a 的值为 :", a)


a = 100

if( a == 10 and 0)
then
   print("a 的值为 10" )
elseif( a == 20  and 0)
then   
   print("a 的值为 20" )
elseif( a == 30 and 0)
then
   print("a 的值为 30" )
else
   print("没有匹配 a 的值" )
end


print("a 的真实值为: ", a )

没有匹配 a 的值
a 的真实值为: 100

Lua 面向对象

  • OOP)是一种非常流行的计算机编程架构。
  • 以下几种编程语言都支持面向对象编程:

C++
Java
Objective-C
Smalltalk
C#
Ruby

面向对象特征

  • 1)
    • 封装:把实体信息、功能、响应都装入一个单独的对象中的特性
  • 2) 继承
    • 继承的方法允许在不改动原程序的基础上对其扩充,
    • 使原功能保存,而新功能也扩展
    • 有利于减少重复编码
  • 3) 多态:
    • 同一操作作用于不同的对象,
    • 可有不同的解释,
    • 产生不同的执行结果。
    • 在运行时,可通过指向基类的指针,来调用实现派生类中的方法
  • 4)抽象:
    • 简化复杂的现实问题的途径
    • 它可以为具体问题找到最恰当的类定义,
    • 且可以在最恰当的继承级别解释问题。

Lua 中面向对象

  • 对象由属性和方法组成。
  • LUA中最基本的结构table,要用table来描述对象的属性
  • lua 中function 可用来表示方法。
  • LUA中的类可以通过 table + function 模拟出来。
  • 继承,可通过 metetable 模拟(不推用,只模拟最基本的对象大部分时间够用)。

  • Lua 中表不仅在某种意义上是一种对象。
  • 像对象一样,表也有状态(成员变量);
    也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;
  • 一个对象在不同的时候也可以有不同的值,但他始终是一个对象;
  • 与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。
  • 表也有成员函数
Account = {balance = 0}
function Account.withdraw (v)
    Account.balance = Account.balance - v
end
Account.withdraw(100.00)
print(Account.balance)

  • 答案是-100
  • 创建一个新的函数,保存在Account对象的withdraw域内,
  • 这样调用
  • Account.withdraw(100.00)

实例

  • 以下类含三个属性:
  • area, length 和 breadth,
  • printArea方法用于打印计算结果:
-- 元类
Rectangle = {area = 0, length = 0, breadth = 0}

-- 派生类的方法 new
function Rectangle:new (o,length,breadth)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  self.length = length or 0
  self.breadth = breadth or 0
  self.area = length*breadth;
  return o
end

-- 派生类的方法 printArea

function Rectangle:printArea ()
  print("矩形面积为 ",self.area)
end

canci

Lua 元表(Metatable)

  • table中可访问对应的key来得value
  • 但无法对两个table操作
  • Lua 提供元表
    • 允许我们改变table行为
    • 每个行为关联对应的元方法

  • 用元表我们可定义计算两个table的相加a+b
  • 当Lua对两个表相加时
    • 先检查两者之一是否有元表
    • 之后检查是否有"__add"字段
  • 若找到,则调对应值
  • "__add"等即时字段
    • 其对应的值(往往一个函数或是table)就是"元方法"

  • setmetatable(table,metatable):
  • 对指定 table 设置元表(metatable),
  • 如果元表(metatable)中存在 __metatable 键值,setmetatable失败
  • getmetatable(table): 返回对象的元表(metatable)

  • 如何对指定的表设置元表
mytable = {}                          -- 普通表 
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表 
  • 以上也可直接写成一行:
mytable = setmetatable({},{})
  • 以下为返回对象元表:
getmetatable(mytable)                 -- 这回返回mymetatable

把元表设置成普通表的元素!

__index 元方法

  • metatable 最常用键
  • 通过键来访问 table时,
    • 如果这个键没值,
    • Lua就会寻找该table的metatable(假定有metatable)中的__index 键

说的非常有道理!

  • 如果__index含一个表格,Lua会在表格中查找相应的键。

other是个table啊!t也是个table啊!!

other = { foo = 3 } 
t = setmetatable({}, { __index = other }) 
t.foo
3
t.bar
nil

意思就是t.foo找不到,就找里面的metatable,看看这个metatable有没有__index键,__index含一个表other,进去找foo

other = { foo = 3 } 
t = setmetatable({aa=123}, { __index = other}) 
print(t.aa)

  • __index含一个函数的话,Lua就调那个函数,
  • table和键会作为参数传递给函数
  • __index 元方法看表中元素是否存在,
    • 如果不存在,返回nil;
    • 如果存在则由 __index 返回结果。
mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return nil
    end
  end
})

print(mytable.key1,mytable.key2)
  • 结果为:
    value1 metatablevalue

  • mytable表赋值为 {key1 = “value1”}。
  • mytable 设置了元表,元方法__index
  • mytable中查key1,找到,返该元素,找不到继续
  • mytable表中找key2,如果找到
    • 返metatablevalue,找不到继续
  • 判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数
  • 元方法中查看是否传入 “key2” 键的参数(mytable.key2已设置),如果传入 “key2” 参数返回 “metatablevalue”,否则返回 mytable 对应的键值

mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

总结

  • Lua 查找一个表元素时的规则,就是如下3步:
  • 在表中查找,如果找到,返回该元素,找不到则继续
  • 判断该表是否有元表,如果没有,返nil,有元表则继续
  • 元表有没有 __index 方法,
    • __index 方法为 nil,返nil;
    • __index是表,则重复 1、2、3;
    • __index 是函数,则返回该函数的返回值

__newindex 元方法

  • 用来对表更新,__index则对表访问
  • 当你给表的一个缺少的索引赋值,
    • 解释器就查找__newindex 元方法:
    • 存在则调用这个函数而不进行赋值

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)

value1
nil    新值2
新值1    nil
  • 表设置元方法__newindex,在对新索引键newkey赋值时(mytable.newkey = “新值2”),会调元方法,而不赋值
  • 如果对已存在的索引键key1,则会赋值,而不调元方法 __newindex。

canci

Lua table

  • 帮助创建不同的数据类型
    • 数组、字典
  • Lua table 用关联型数组
    • 可用任意类型的值作数组索引
    • 但不能是 nil

  • 不固定大小,可扩容
  • 也是通过table来解决
    • 模块(module)、包(package)和对象(Object)的
    • string.format表示使用"format"来索引table string

table(表)的构造

  • 构造器是创建和初始化表的表达式。
  • 表是Lua特有的功能强大的东西。
  • 最简单的构造函数是{},用来创建一个空表。可以直接初始化数组:
-- 初始化表
mytable = {}
-- 指定值
mytable[1]= "Lua"
-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存
  • 为 table a 并设元素
  • 将a赋给b
  • 则a与b都指向同一内存。
  • a 设为 nil ,则 b 同样能访问 table 的元素。
  • 如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。

canci

Lua 模块与包

  • 模块类似一个封装库
  • 5.1 开始,Lua 加入标准的模块管理机制
  • 把一些公用的代码放在一个文件里
  • 以 API 接口的形式在其他地方调
    • 代码的重用和降低代码耦合度

  • Lua 模块由
    • 变量、
    • 函数
    • 等已知元素组成的 table
  • 创建一个模块很简单,就是创建一个 table
    • 然后把需要导出的常量、函数放入其中
    • 最后返回这个 table
  • 创建自定义模块 module.lua
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module
  • 模块结构就是一个table结构
    • 可像操作调用table里的元素那样来操作调用模块里的常量或函数
  • func2为程序块局部变量
    • 私有函数
    • 必须通过模块里的公有函数来调

require 函数

  • require的函数用来加载模块
    require("<模块名>")

    require “<模块名>”

canci

C/C++嵌入Lua

  • Lua是一门嵌入式语言,

    • 其他应用可以链接它,从而将它作为一个库,
    • 以便使用它的所有特性。
  • OS X环境下,如何在C/C++代码中嵌入Lua。

编译库文件

  • 已完成lua库文件的编译过程,并生成了静态库 liblua.a:

创建C++控制台应用程序;

添加头文件搜索路径;

添加lua库文件liblua.a;

输出Hello World

canci

初始化Lua环境

  • “如何在OS X中,初始化Lua开发环境”。
  • 适用于初学者,尤其是带着这样的疑惑的读者:“我想学习Lua语言,用它作为编程语言,来进行项目开发,该如何配置开发环境?”

  • Lua官网 http://www.lua.org/download.html
  • 上下载最新的lua-5.3.4.tar.gz
  • 解压到指定文件夹,这里设置为:
/Users/huaxingzheng/develop
/Users/huaxingzheng/develop/lua-5.3.4
cd lua-5.3.4
make macosx test
  • 安装成功后,屏幕会输出
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio


  • 现为lua添加查找路径,打开Terminal,
  • 粘贴运行以下内容
# Add environment variable LUA_ROOT for Lua5.3.4
export LUA_ROOT=/Users/huaxingzheng/develop/lua-5.3.4/src
export PATH=$LUA_ROOT:$PATH
  • OK!,你可以在任意位置调用 lua

cacni

Lua 函数

  • Lua 提供许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。

  • Lua 函数主要两用途:

  • 1.完成指定的任务,这种情况下函数作为调用语句使用;

  • 2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。

Lua 函数定义格式如下:

optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end
  • optional_function_scope:
    • 可选的制定函数是全局函数还是局部函数,
    • 未设置该参数默认为全局函数,
    • 如果你需要设置函数为局部函数需要使用关键字 local。
  • result_params_comma_separated:
    • 函数返回值,
    • 可以返回多个值,每个值以逗号隔开。

canci

Lua 教程

  • 轻量小巧的脚本语言
    • 用标准C编写并以源代码形式开放
  • 里约热内卢天主教大学研究小组93年

设计目的

  • 为了嵌入应用程序中
  • 从而为应用程序提供灵活扩展和定制功能

Lua 特性

  • 轻量级:
    • 用标准C编写并以源代码形式开放
    • 编译后仅仅一百余K
    • 可方便的嵌入别的程序
  • 可扩展: Lua提供易于使用的扩展接口和机制
    • 由宿主语言(通常C或C++)提供这些功能,Lua可用它们
    • 就像是本来就内置的功能
  • 其它:
  • 支持面向过程编程和函数式编程
  • 自动内存管理
    • 只提供一种通用类型的表
    • 用它可实现数组,哈希表,集合,对象
  • 语言内置模式匹配;闭包;函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
  • 通过闭包和table可方便支持面向对象编程所需要的一些关键机制,
    • 数据抽象,虚函数,继承和重载等

Lua 应用场景

  • 游戏开发
  • 独立应用脚本
  • Web 应用脚本
  • 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
  • 安全系统,如入侵检测系统

第一个 Lua 程序

print(“Hello World!”)

Lua 基本语法

交互式编程

  • 交互式编程模式lua -i 或 lua 来启用
$ lua -i 
$ Lua 5.3.0  Copyright (C) 1994-2015 Lua.org, PUC-Rio
  • 命令行中输入:

print(“Hello World!”)

  • 按下回车键,输出结果

脚本式编程

  • 代码保存到一个以 lua 结尾的文件,并执行
  • 将如下代码存储在名为 hello.lua 的脚本文件
print("Hello World!")
print("www.runoob.com")
$ lua hello.lua
Hello World!
www.runoob.com

  • 我们也可以将代码修改为如下形式
#!/usr/local/bin/lua

print("Hello World!")
print("www.runoob.com")
  • 指定了 Lua 的解释器 /usr/local/bin directory。
  • # 号标记解释器会忽略它。
  • 接下来我们为脚本添加可执行权限,并执行:

./hello.lua 
Hello World!
www.runoob.com

注释

  • 两个减号是单行注释:
  • 多行注释
--[[
 多行注释
 多行注释
 --]]

标示符

  • 标示符用于定义一个变量,函数获取其他用户定义的项。
  • 以一个字母或下划线 _ 开头后加上0个或多个字母,下划线,数
  • 不要用下划线加大写字母的标示符,因为Lua的保留字也是这样的。

  • 不允许用如 @, $, 和 % 来定义标示符。
  • 区分大小写
  • 一些正确的标示符:
    mohd zara abc move_name a_123
    myname50 _temp j a23b9 retVal

关键词

  • 以下列出Lua 的保留关键字。
  • 保留关键字不能作为常量或变量或其他用户自定义标示符:

and break do else elseif end false for
function if in local nil not or repeat
return then true until while goto

  • 一般约定
  • 下划线开头连接一串大写字母的名字(_VERSION)被保留
    • Lua 内部全局变量

全局变量

  • 默认变量总认为是全局
  • 全局变量不需声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。
> print(b)
nil
> b=10
> print(b)
10
> 

  • 如果你想删一个全局变量,只需要将变量赋值为nil。
    b = nil
    print(b) --> nil
  • 变量b就好像从没被使用过一样。
  • 当且仅当一个变量不等于nil时,这个变量即存在。

canci

Lua 数据类型

  • Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。
  • 值可存在变量中,作为参数传递或结果返回
  • 8 个基本类型:
    • nil、boolean、number、
    • string、userdata、function、
    • thread 和 table

  • nil最简单,只有值nil属于该类,
  • 一个无效值(条件表达式中相当于false)。

  • boolean含两个值:false和true。

  • number
  • 双精度类型的实浮点数

  • string
  • 一对双引号或单引号来表示

  • function
  • C 或 Lua 编写的函数

  • userdata
  • 任意存储在变量中的C数据结构

比如你lua_pushlightuserdata一个指针进入lua里面,你在lua里面用type查看这个变量,他就是userdata类型的

  • thread
  • 执行的独立线路,用于执行协同程序

  • Lua 中的表(table)其实是一个"关联数组
  • 索引可以是数字、字符串或表类型。
  • Lua 里,table的创建是通过"构造表达式"完成,
    • 最简单构造表达式是{},用来创建一个空表。

print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(X)))            --> string

和你没完!

canci

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐