Lua 最全的快速入门教程_lua编程零基础教学-程序员宅基地

技术标签: Lua  lua  

目录

一、Hello World

二、注释

三、标识符

四、关键字

五、全局变量

六、Lua 数据类型

七、Lua 数据类型 - String

八、Lua 数据类型 - table

九、Lua 数据类型 - function

十、Lua 数据类型 - userdata

十一、Lua 变量

十二、Lua 循环

十三、Lua 函数

十四、运算符

十五、迭代器

十六、Lua 模块与包

十七、Lua 元表的使用

十八、Lua 协程

十九、 Lua 垃圾回收

二十、Lua 面向对象


一、Hello World

#!/usr/local/bin/lua
print("helloWorld");
lua test.lua

二、注释

单行注释: -- 注释

多行注释:

--[[

     注释内容

--]]

三、标识符

不允许使用特殊字符(@ $ % 等),只允许字母、数字、下划线,区分大小写

四、关键字

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

五、全局变量

#!/usr/local/bin/lua

print(b)                                -- 访问一个未定义的全局变量合法,值为 nil

c = 10
print(c)

c = nil                                 -- 若要删除一个变量,将其赋值为 nil

六、Lua 数据类型

  • nil :无效值
  • boolean:包含 true / false
  • number:双精度double类型的实浮点数
  • string:一对 单引号或双引号表示的字符窜
  • function:函数 
  • userdata:任意存储在变量中的C数据结构
  • thread:执行的独立线程
  • table:关联数组

type() :获取某个变量的数据类型

七、Lua 数据类型 - String

#!/usr/local/bin/lua

string1 = "helloworld"                          -- 字符窜

string2 = [[
i love china
i love asia 
]]                                              -- 表示一块字符窜

-- print(string1 + 2)                           -- 字符串与数字相加时,Lua会尝试这个数据字符串转成数字,若失败会报错

string3 = string1..string2                      -- 通过 .. 连接字符串

print(#string3)                                 -- #,放在字符窜前,用于计算字符串长度

八、Lua 数据类型 - table

#!/usr/local/bin/lua

-- table 可看做是关联数组,索引可以是数字或字符串

local table1 = {}                                       -- 创建一个空table

local table2 = {"apple", "pear"}                        -- 创建与初始化一个table

table1["love"] = 1                                      -- 直接赋值

for k, v in pairs(table2) do
        print(k, v)
end                                                     -- 循环table

-- Lua中初始索引为1

九、Lua 数据类型 - function

#!/usr/local/bin/lua

-- 重点1:函数可以存在变量中

function test(n)
        if n == 1 then
                return 1
        else 
                return 0
        end
end

print(test(1))                                  -- 调用函数

test2 = test                                    -- 将函数test存放在test2中

print(test2(1))                                 -- 相当于调用test函数

-- 重点2:function 可以以匿名函数的方式通过参数传递

function test3(n, func) 
        func(n)
end

test3(1, function(x)                            -- 匿名函数的使用
        return x
end)

十、Lua 数据类型 - userdata

表示一种由应用程序或 C 创建的类型,将 C 的任意数据类型数据(struct、指针等)存储到 Lua 中调用。

十一、Lua 变量

#!/usr/local/bin/lua

-- 重点1:全局变量 / 局部变量

a = 5
local b = 10                            -- 显式指定为局部变量

function joke()
        c = 10                          -- 默认是全局变量
        local d = 20                    -- 设置为局部变量
end

joke()
print(c, d)                             -- 返回 10, nil

-- 重点2:同时赋值

x, y = 10, 20

x2 = 10; y2 = 10

-- 重点3:table中当索引为字符串类型时,可以通过 . 进行访问

table = {}

table["love"] = 1

print(table.love)

十二、Lua 循环

#!/usr/local/bin/lua

-- for 循环
-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1

-- for var = exp1, exp2, exp3 do
--              <执行体>
-- end

for i = 1, 100, 10 do
    print(i)
end


-- while 循环

x = 0
while (x < 10) 
do
    x = x + 5
    print(x)
end


-- repeat..until 循环

a = 0
repeat 
    print(a)
    a = a + 5
until(a > 9)

需要注意的是 Lua 中 0 为 true

十三、Lua 函数

1)通过 local 关键字指定为局部函数,否则默认是全局函数

2)函数可返回多个值 return a, b

3)可变参数:

#!/usr/local/bin/lua

-- 计算平均值的函数
function average(...)                           -- 通过 ... 声明函数的参数可变,可传入不确定的参数个数。
    result = 0

    local arg = {...}                               -- lua将参数放在arg表中

    for i, v in ipairs(arg) do
        result = result + v
    end

    return result / #arg
end

print(average(1, 2, 3, 4, 5))

十四、运算符

1)不等于 ~=,^ 幂运算,如 a = 10 , a ^ 2 = 100

2)支持 and or not 判断,如 if (a and b)

3)连接两个字符串 .. ,如 a .. b

4)获取字符串或table的长度,如 # "Hello" = 5

十五、迭代器

#!/usr/local/bin/lua

-- 重点1:无状态迭代器,避免创建闭包花费的额外代价

function square(max, current)
    if current < max then
        current = current + 1
    return current, current * current
    end
end 

for i, n in square, 3, 0                                          -- 调用迭代器
do
    print(i, n)
end

-- 重点2:多状态迭代器

array = {"Lua", "Php"}

function iter(collection)
    local index = 0
    local count = #collection

    return function ()                                        -- 闭包函数 
        index = index + 1
        if index <= count then
                return collection[index]                  -- 返回迭代器当前元素
        end
    end
end

for el in iter(array)
do
    print(el)
end

十六、Lua 模块与包

1)基本使用

定义一个模块 module.lua:

#!/usr/local/bin/lua

module = {}                                 -- Lua 的模块是由变量、函数等元素组成的表

module.constant = "这是一个常量"             -- Lua 定义包中一个常量

function module.func1()                     -- 模块外可访问的函数
    print("这是一个公有函数")
end

local function func2()                      -- 私有函数,只能本程序内部使用
    print("这是一个私有函数")
end

function module.func3()                     -- 让私有函数在外部可以访问
    func2()
end

return module                               -- 返回这个模块

定义一个调用模块的 lua 文件 useModule.lua : 

#!/usr/local/bin/lua

local m = require("module")                                     -- 引入模块

print(m.constant)                                               -- 获取模块的值

m.func1()

执行 lua useModule.lua 可见 module 模块的值被引入

2)加载机制

require 用于搜索lua文件的路径存放在 package.path 这个全局变量中。Lua 启动后,会以环境变量 LUA_PATH 的值初始化这个环境变量。如果没有找不到该环境变量,使用编译时的默认路径初始化。

如果找到目标文件,调用 package.loadfile 加载模块,否则就找 C 程序库,从 package.cpath 获取搜索文件路径,搜索类似 .so 或 .dll 文件,找到通过 package.loadlib 加载

3)C包

Lua 与 C 可以很好地结合,可使用 C 为 Lua 写包。

local path = "/usr/local/lua/lib/libluasocket.so"               

-- loadlib 函数提供动态链接功能,第一个参数是库的绝对路径,第二个参数是库中的初始化函数

local f = assert(loadlib(path, "luaopen_socket"))               

f()                                                            -- 打开 C 包的库

十七、Lua 元表的使用

1)__index 元方法

#!/usr/local/bin/lua

-- 重点1:创建元表

mytable = {}
mymetatable = {}
setmetatable(mytable, mymetatable)                      -- 把mymetatable设置为mytale的元表
getmetatable(mytable)                                   -- 返回mymetatable

-- 或者直接写成一行创建元表 mytable = setmetatable({}, {})

-- 重点2:__index 元方法

other = { foo = 3 }

table = setmetatable({}, { __index = other })

print(table.foo)                        -- 通过键访问表时,如果键没有值,寻找元表对应的 __index 方法获取

table2 = setmetatable({ foo = 4 }, { __index = other })

print(table.foo)                        -- 返回3而不返回4,说明 __index中若有访问的键对应的值,优先级要高于表中的键值 

table3 = setmetatable({}, { __index = function(table3, key)
    if key == 'key2' then
        return "ok"
    else
        return nil
    end
end
})

print(table3.key2)                      -- 演示 __ index 中使用函数返回

2)__newindex 元方法

#!/usr/local/bin/lua

-- __newindex 元方法

emptyTable = {}

table = setmetatable({key1 = "a"}, {__newindex = emptyTable})

print(table.key1)           -- 如果键值存在直接返回

table.key2 = "b"            -- 键值不存在则调用元表__newindex方法,将key2的属性赋值给 emptyTable

print(table.key2)           -- nil
print(emptyTable.key2)      -- "b"

3)为表添加运算符

#!/usr/local/bin/lua

-- 该函数求出table中最大的键

function maxTableKey(table)
    local max = 0
    for k, v in pairs(table) 
    do
        if max < k then
            max = k
        end
    end
    return max
end

-- 两表相加

mytable = setmetatable({1, 2, 3}, {__add = function (mytable, newtable) 
    for i = 1, maxTableKey(newtable) do
        table.insert(mytable, maxTableKey(mytable) + 1, newtable[i]);
        -- 插入newtable的元素到mytable表中
    end
    return mytable                          -- 返回插入后的表
end
})


testtable = {4, 5, 6}

mytable = mytable + testtable                   -- 自动调用元表的 __add 方法

for k, v in ipairs(mytable) do
    print(v)
end

4)__call 元方法

#!/usr/local/bin/lua

table = setmetatable({1, 2, 3}, {__call = function (table, n) 
    print("call me "..n)
end
})

print(table(100))                       -- 当元表当做函数被使用时,调用__call方法

5)__tostring 元方法

#!/usr/local/bin/lua

table = setmetatable({}, { __tostring = function () 
    return "i am tostringing"
end
})

print(table)                                    -- 打印一个table变量时会调用__tostring元方法

十八、Lua 协程

Lua 协程与线程类似,拥有独立的堆栈、独立的局部变量、独立的指令指针

一个具有多线程的程序可以运行几个线程,而协程需要彼此协作运行。在任一指定时刻,只有一个协同程序在运行,且这个正运行的协程只有在明确被挂起的时候才被挂起。

coroutine.create() 创建 coroutine , 返回 coroutine,参数是一个函数
coroutine.resume() 重启 coroutine,和 create 配合使用
coroutine.yield() 挂起 coroutine
coroutine.status() 查看 coroutine 状态:dead \ suspend \ running
coroutine.warp()

作用与 create 相同,调用返回的函数就进入 coroutine

coroutine.running() 返回正在运行的协程与布尔值,true代表当前是主协程
#!/usr/local/bin/lua

co = coroutine.create(function(i)
    print(i)
end
)

coroutine.resume(co, 1)                                 -- 输出1

print(coroutine.status(co))                             -- 输出dead
#!/usr/local/bin/lua

co = coroutine.wrap(function(i)
    print(i)
end
)

co(1)                                                   -- 输出1
#!/usr/local/bin/lua

co = coroutine.create(function()                    -- create 创建一个 coroutine
    for i = 1, 10
        do
        print(i)
        if i == 3 then
            print(coroutine.status(co))             -- 查看coroutine状态
            print(coroutine.running())              -- 查看正在运行的coroutine
        end

     coroutine.yield()                              -- 挂起coroutine
     end
end
)


coroutine.resume(co)                                -- 重启coroutine , 输出1
coroutine.resume(co)                                -- 重启被挂起的coroutine,输出2
coroutine.resume(co)                                -- 功能同上,输出3

print(coroutine.status(co))
print(coroutine.running())                          -- true 代表是主协程



-- 最终输出:

1
2
3
running
thread: 0x2106bb8       false
suspended
thread: 0x2100018       true
#!/usr/local/bin/lua

function foo(a) 
        print("foo_out", a)
        return coroutine.yield(2*a)       -- yield的参数将返回给resume
end

co = coroutine.create(function(a, b) 
        print("first ", a, b)

        local r = foo(a + 1)

        print("second ", r)

        local r, s = coroutine.yield(a + b, a - b)

        print("third ", r, s)

        return b, "over"
end
)

print(coroutine.resume(co, 1, 10))  
                                 
-- 第一次调用,将1,10传入给create的a b 参数,直到第5行函数挂起,返回2*a

print(coroutine.resume(co, "r"))                     
                    
-- 第二次调用,由于协程已经产生,重启协程并将参数 r 赋值给第5行被挂起的断点 coroutine.yield ,因而 r = "r" 即此时 coroutine.yield 将 return "r" 使得第11行 local r = "r"

print(coroutine.resume(co, "x", "y"))                            
print(coroutine.resume(co, "x", "y"))


-- 输出:
--[[
--first   1       10
--foo_out 2
--true    4
--second  r
--true    11      -9
--third   x       y
--true    10      over
--false   cannot resume dead coroutine
--]]

十九、 Lua 垃圾回收

Lua 采用自动内存管理机制,通过运行垃圾收集器收集所有死对象(Lua中不可能再访问到的对象)来完成自动内存管理工作。

Lua 通过控制垃圾收集器间歇率(需要开启新的循环前等待的时间)、步进倍率(控制收集器运作速度相对于内存分配的速度)来对垃圾进行回收

#!/usr/local/bin/lua

table = {"apple", "orange", "juice"}

print(collectgarbage("count"))                                  -- 查看此时 lua 使用的总内存数,以kb为单位

table = nil

print(collectgarbage("count"))                                  -- 此时还没被回收
print(collectgarbage("collect"))                                -- 做一次完整的垃圾收集循环
print(collectgarbage("count"))                                  -- 查看回收后使用的内存

--------------------
23.640625
23.744140625
0
23.0546875

二十、Lua 面向对象

Lua 使用表描述对象的属性,Lua 的函数用来表示方法,类可通过表+函数模拟出来。

1)简单创建类

#!/usr/local/bin/lua

Shape = {area = 0}                              -- Shape 作为类的元表

function Shape:new (o, side)                    -- 声明一个类,相当于 __ construct() 类的构造方法
    o = o or {}

    setmetatable(o, self)                       -- 这里的self指的是Shape

    self.__index = self                         -- 当访问o.area,因为o中没有area,因此会访问Shape中的area

    side = side or 0

    self.area = side * side                     -- 声明新的类属性
    self.hello = 1

    return o
end

function Shape:printArea()                      -- 声明类的成员方法
    print("Area is ", self.area)
end


-- 创建对象

shaper = Shape:new(nil, 10)

shaper:printArea()                              -- 访问方法

print(shaper.hello)                             -- 访问成员属性

2)继承

#!/usr/local/bin/lua

Shape = { area = 1 }

function Shape:new (o, side) 
    o = o or {}
    
    setmetatable(o, self)

    self.__index = self

    side = side or 0 

    self.area = side * side

    return o
end

function Shape:printArea()    
        print(self.area) 
end


-- 继承

Square = Shape:new()

function Square:new(o, side) 
    o = o or Shape:new(o, side)                  -- 使用 Shape 表作为父类

    setmetatable(o, self)

    self.__index = self

    return o
end


-- 使用继承类

square = Square:new(nil, 10)

square:printArea()

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/panguangyuu/article/details/88775896

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签