zoukankan      html  css  js  c++  java
  • Siki_Unity_3-8_Lua编程(未完)

    Unity 3-8 Lua编程

    任务1&2&3:前言

    课程内容:
      Lua从入门到掌握
      为之后的xLua和其他热更新方案打下基础

    任务4:Lua简介

    Lua是轻量小巧的脚本语言--无需编译,用标准c语言编写,开源
      目的是为了嵌入应用程序中,为应用程序提供灵活的扩展和定制功能
      可以很方便地与其他程序进行集成(如C++, C#, Java等)
        -- 因为Lua无需编译,对于某些功能,如果不方便重新编写,可以使用Lua进行功能扩展

    Lua应用场景:
      游戏开发
      独立应用脚本
      Web应用脚本
      扩展和数据库插件
      安全系统(如入侵检测系统)

    Lua和c#的区别:
      Lua可以在几乎所有操作系统/平台运行
        可以很方便的更新代码,代码更新后无需重新安装 -- 后续的热更新方案
        不需要c#那样重新编译打包
      c#只能在特定的操作系统中进行编译成dll文件,然后打包进安装包在其他平台运行
        在移动平台上不能更新替换已有的dll文件,除非重新下载安装包

    学习资料:
      Programming in Lua
      www.runoob.com/lua/lua-tutorial.html -- 菜鸟教程
      www.luaer.cn -- Lua中国开发者
      官网:www.lua.org

    任务5&6:Lua的安装(SciTE && LuaDist) 和第一个Lua程序

    http://www.runoob.com/lua/lua-environment.html
    SciTE -- https://github.com/rjpcomputing/luaforwindows/releases,带IDE
    LuaDist -- 无IDE

    任务7:注释

    -- 单行注释

    --[[ 多行注释 ]]--

    -- 单行注释
    --[[
        多行注释
        小技巧:在多行注释开头再加一个-,会使多行注释代码块生效
        原因是第一行和最后一行都变成了单行注释
    ]]--
    
    ---[[
        print("Execute")
    --]]

    任务8:标识符命名规则和关键字

    标识符:字母或_开头,后跟0或多个字母或_或数字

    不推荐"_跟大写字母作为标识符",比如"_NAME",这是lua的保留字命名规则(Lua内部使用的变量名)

    标识符区分大小写

    任务9、21:全局变量和局部变量

    默认情况下的变量都是全局的
    全局变量不需要声明,给一个变量赋值后就相当于创建了这个全局变量,比如 a = 10
      访问一个没有赋值的全局变量,此时不会报错,但是变量不存在,比如 print(b) 的结果为 nil
      而如果需要删除一个全局变量,赋值为nil即可,如 a = nil,删除后则a不存在

    局部变量的声明:local b = 10
      局部变量的生命周期为:从声明开始,到所在语句块结束
      如果是语句块是在最外围,则整个lua脚本文件的语句执行完后才被销毁

    function f () 
        a = 1
        local b = 2
        -- a为全局变量,b为局部变量
    end
    
    f()      -- 注意,如果这边没有调用函数f(),则上面函数定义中的变量是没有被创建的
    
    print(a)    -- 1
    print(b)    -- nil

    函数也是可以通过local来修饰为局部函数的

    局部变量和全局变量的重名规则:
      有局部变量时局部变量优先

    一般而言,访问局部变量的速度会比访问全局变量快,而且局部变量在生命周期结束后会被销毁释放内存空间

    任务10~20:数据类型的简介

    基本类型:

    nil -- 只有一个值nil,表示无效值,条件表达式内相当于false

    boolean -- true / false

    number -- 双精度实浮点数

    string -- "string" 或 'string'

    function -- 函数

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

    thread -- 独立执行的线路,协程(非线程)

    table -- 表(关联数组),索引为数字或字符串,{}表示一个空表

    使用type可以获取变量或者值的类型,如

    print(type("hellolua"))    -- string
    print(type(10))    number
    print(type(1.1)    number
    print(type(print))    function
    print(type(type))    function
    print(type(nil))    nil
    print(type(x))    nil

    nil:nil类型只有一个值nil,表示无效值,比如当变量未被赋值时,即为nil值

    给变量赋值nil后,表示将该变量销毁,释放内存

    boolean:nil值视为为false,其他变量值都视为true,比如if(10)是true

    string
      表示方法:"" 或 ‘’ 或 [[ ]] (表示多行)
      "string"
      'string'
      [[str
        in g ]]

      字符串的拼接,不能用 + 号,只能用 .. ,如 print("a".."b") --> "ab"     ;     print(2..6) --> 26
      print("2" + "6") --> 8 会自动转换为number类型
      #表示字符串长度(字节数),如  s = "ab呀"; print(#s) --> 4

    table:

    构造方法及使用

    table1 = { }  -- 构造表达式,得到一个空表
    print(table1)        -- -> table:00A89600
    print(table1.key1)    -- -> nil
    
    table2 = {key1 = 100, key2 = "aaa"}
    print(table2.key1)        -- ->100
    print(table2["key1"])    -- ->100
    
    table3 = {"111", "222", "hello"}
    print(table[2])       -- -> 222 -- Lua中没有数组,用table表示数组。
    -- 在Lua中,索引一般是从1开始算的,不是0
    
    -- table的索引
    for key,val in pairs(table3) do
        print(key..":"..val);
    end
    -- -> 1:111 2:222 3:hello 

    table的大小不是固定的,可以很灵活的进行增删查改

    -- 对于字典形式
    tbl = {key1 = "aaa"}
    -- 修改
    tbl.key1 = 123    -- 类型可以不相同
    
    -- 增加
    tbl["key2"] = "value"
    tbl.key222 = "value"
    tlb[10] = 1000
    
    -- 删除
    tbl.key2 = nil    -- 此时进行遍历就不会遍历到key2了
    
    -- 对于数组形式(实质上还是字典,只不过把自动索引作为了key)
    tbl = {"1", "a"}
    tbl[2] = "b"        -- 修改
    tbl[3] = "c"        -- 增加
    tbl[2] = nil         -- 删除 -- 注意,这里的数组本质上还是键值对的形式
    -- 比如这边把索引为2的删除后,遍历可得到 --> 1:1  3:c (索引不是连续的)
    -- 也同样可以添加键值对
    tbl["key5"] = "value5"
    
    -- 删除整个表
    tbl = nil

    function:函数

    不需定义返回值类型,但是可以返回任意类型返回值

    函数体为 从 function name(argument) 到 end 之间

    function f1(n)
        print(n)
        return n
    end

    可作为一个类型作赋值操作

      f2 = f1 -- 此时f2也为一个function类,函数内容和f1一样

    可以作为参数传递

    function func1(table fun)
        for key, value in pairs(table)
            fun(key, value)
        end
    end
    
    function func2(key, value)
        print(key..":"..value)
    end
    
    func1(table, func2) -- 遍历table并输出key,value

    匿名函数:只能使用一次,不用定义函数名

    -- 以上一段代码为例,调用的时候
    func1(table, 
        function (key, value)
            print(key..":"..value)
        end
    )
    -- 遍历table输出键值对

    thread:协同程序

    不是线程

    拥有自己独立的栈、局部变量和指令指针

    可以共享全局变量和其他大部分东西

    任意时刻,协程只能运行一个,只有被挂起 suspend 的时候协程才会暂停

    userdata:自定义类型

    用于表示由应用程序或C/C++创建的类型,可以将C/C++任意数据类型 (通常为struct和指针) 存储到lua变量中进行调用

    任务22:多变量赋值

    a, b, c = 1, 2, "c"

    a, b = b, a  -- 并不是简单的a = b; b = a;,而是很方便的交换了a和b的值 -- 结果为a = 2, b = 1
      因为lua是将右边的值全部计算完后,再统一赋值的

    a, b = 10, 20, 30 -- 30会被忽略

    a, b, c = 10, 20   -- 未赋值的变量会初始化为默认值,即为nil

    函数function也是可以直接返回多个值的
      function test()
        return 1,2
      end
      a, b = test()

    任务23、24、26:流程控制

    while循环

    while (condition) do
      statements
    end

    condition的括号可加可不加

    for循环

    数值for循环

    for var = start, end, step do
      statements
    end

    var从start到end (inclusive),每次增加step
    step未指定时默认为1

    泛型for循环

    for key, value in pairs (table) do
      statements
    end

    repeat unitl循环(和do while流程相同,逻辑相反):

    repeat
      statements
    until (condition)

    直到满足condition后,就跳出循环(而不是do while的继续循环)

    if判断

    if (condition) then
      statements
    end

     

    -- 注意,数值0表示true,nil值表示false

    if (condition) then
      statements
    elseif (condition) then
      statements
    else
      statements
    end

    任务27、28:function详解

    [local] function name(arg1, arg2, ..., argn)
      statements
      [return value1, value2, ... valuen]
    end

    1. function本质为变量类型,因此可以作为数据直接赋值,也可以作为参数传递

    2. 可直接返回多个值,可用多变量赋值的方式接收返回值(如果接收返回值的变量数不对,则遵循多变量赋值的规则)
      如:func返回值为4个,调用处代码 a, b = func(),则后两个返回值就没有获取到了

    3. 可变参数,传递的参数个数可以是多个

    -- 定义时 
    function func(...)
        print(arg)  
        -- 这边会将多个参数封装成一个table类型,以便使用
        -- table中保存了所有传入的参数,最后一位保存了参数的总个数
        local arg = {...}
        -- 此时args里保存的为所有传入的参数,不带最后一个总个数了
    end
    
    -- 调用时
    func(a)
    func(a, b)

    任务29:运算符

    数学运算符:

    ^  -- 求幂

    % -- 求余(可对小数进行求余)

    关系运算符:

    ~=  -- 不等

    逻辑运算符:

    and  -- 与

    or  -- 或

    not  -- 非

    其他运算符:

    ..  -- 字符串连接

    #  -- 取得字符串长度

    任务32、33:字符串常见操作

    newstring = string.upper(oldstring)
    newstring  = string.lower(oldstring)
    newstring  = string.gsub(oldstring, "o", "r", num)  -- 将str1中的 o 替换成 r, num 表示替换的最大次数,可以不传
    index = string.find(str, "substr", num)  -- 从num开始,搜索str是否有子字符串substr,返回子字符串开始的索引
    newstring = string.reverse(oldstring)
    str = string.format("%02d", month)
    str = string.char(97, 98, 99)  -- 对应ASCII码。abc
    integer = string.byte("ABCD", num)  -- 返回num个字符对应的值。不写num时默认为第一个字符
    newstring  = string.rep(oldstring, count)  -- oldstring重复count次
    string.gmatch()/ string.match() -- 正则表达式

    任务35:多维数组

    array = { {"a", "b"}, { "1", "2"}, {"xx", "yy"} }
    print(array[1][1])  -- 输出a

    任务36、37:迭代器函数

    pairs 遍历 table,表中所有的key和value
    ipairs 按索引遍历,从1开始,递增遍历,遇到nil值就停止

    自定义迭代函数:

    .......

    ......

    ......

    ......

    ......

    .......

    ......

    ......

    ......

    ......

    .......

    ......

    ......

    ......

    ......

    .......

    ......

    ......

    ......

    ......

    任务50~54:协同程序

    Lua中协程和线程的区别有:线程是由CPU进行任务调度的,可以视为同一时间可以同时运行多个线程
      而协程是在同一个线程中的,同一时刻只能在运行一个协程,需要代码控制多协程的协作,对协程进行挂起或继续等操作

    基本用法:

    -- 定义方法1
    co = coroutine.create (
        function (a,b)    -- 这里是一个匿名函数
            print(a)
        end
    )
    
    -- 对应的调用
    coroutine.resume(co, 20, 30)
    
    -- 定义方法2
    co = coroutine.wrap (
        function (a,b)    -- 区别只有调用的函数不同,这边是wrap
            print(a)
        end
    )
    -- wrap对应的调用,直接启动即可,不需通过resume()
    co(20,30)
    
    -- 挂起:在上面定义的匿名函数中,使用coroutine.yield()语句即可挂起协程
    co = coroutine.wrap (
        function (a,b)    -- 区别只有调用的函数不同,这边是wrap
            print(a)
            coroutine.yield()
            print(b)
        end
    )
    
    -- 恢复运行协程 -- 注意:当一个协程执行完毕return后,再进行resume并传参进去,并不能再次开始执行协程
    coroutine.resume(co)
    
    -- 返回值
    -- 假设上面的匿名函数的最后一句为
    return a+b, a-b
    -- 调用/继续的时候接收返回值(如果没有执行到return语句,只会有第一个true/false的返回值表示该次调用/继续是否成功)
    res1, res2, res3 = coroutine.resume(co, 20,30)
    print(res1, res2, res3)
    -- 结果为true, 50, -10,其中第一个返回值表示resume成功与否
    -- 如果想在挂起的时候有返回值的话,在yield中传递参数
    coroutine.yield(a*b)
    -- 调用/继续resume的时候会得到额外的返回值
    res1, res2 = coroutine.resume(co, 20, 30)
    -- res1 = true, res2 = 600

    其他函数:

    coroutine.status(co)
      有三个值:
        running:协程正在执行过程中
        suspended:协程未开始或暂停挂起后
        dead: 协程执行完毕后

    coroutine.running()
      当前正在运行的协程,返回值为协程的地址
      如果当前没有正在运行的协程(包括未开始、挂起都不算正在运行),则输出nil

    加大难度:协同程序内部和外部的数据交流

    https://www.runoob.com/lua/lua-coroutine.html

    function foo (a)
        print("foo 函数输出", a)
        return coroutine.yield(2 * a) -- 返回  2*a 的值
    end
     
    co = coroutine.create(function (a , b)
        print("第一次协同程序执行输出", a, b) -- co-body 1 10
        local r = foo(a + 1)
         
        print("第二次协同程序执行输出", r)
        local r, s = coroutine.yield(a + b, a - b)  -- a,b的值为第一次调用协同程序时传入
         
        print("第三次协同程序执行输出", r, s)
        return b, "结束协同程序"                   -- b的值为第二次调用协同程序时传入
    end)
           
    print("main", coroutine.resume(co, 1, 10)) -- true, 4
    print("--分割线----")
    print("main", coroutine.resume(co, "r")) -- true 11 -9  -- 此处resume的参数中,除了第一个参数,剩下的参数将作为yield的参数
    print("---分割线---")
    print("main", coroutine.resume(co, "x", "y")) -- true 10 end
    print("---分割线---")
    print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
    print("---分割线---")
    
    --[[
    第一次协同程序执行输出    1    10
    foo 函数输出    2
    main    true    4
    --分割线----
    第二次协同程序执行输出    r
    main    true    11    -9
    ---分割线---
    第三次协同程序执行输出    x    y
    main    true    10    结束协同程序
    ---分割线---
    main    false    cannot resume dead coroutine
    ---分割线---
    ]]--

    任务55~58:文件操作

    I/O的简单模式:

    file = io.open(filename [, mode])
      mode:
      r -- 只读,文件必须存在
      w -- 只写,若文件已存在则清空内容后开始写入,若文件不存在则创建新文件开始写入
      a -- 附加方式打开只写文件,若文件不存在则创建,若文件存在则从文件尾(保留EOF符)开始写入
      r+ / w+ / a+:文件是可读写文件
      b -- 针对二进制文件,进行二进制模式的打开

    io.flush() -- 向文件中写入缓冲中的所有数据

    -- 读取
    file = io.open("name.txt", "r")
    io.input(file)
    io.read()    -- 读取文件流中的一行数据
    io.read("*l")     --默认值,和io.read()一样,读取下一行,在文件尾EOF处返回nil
    io.read("*n")    -- 读取一个数字
    io.read("*a")    -- 读取文件中的所有内容
    io.read(9)    -- 读取之后的9个字符
    io.close(file)
    
    -- 写入
    file = io.open(..., "a")
    io.output(file)
    io.write("new string")
    io.close(file)

    I/O的完全模式:需要同一时间处理多个文件时

    以file:的方式进行调用(注意是 : ),而不是io.的方式

    file = io.open("xx.txt","a")
    file:read()
    file:write("xxxxx")
    file:close()

    file:seek(optional whence, offset)  -- 把光标移到对应位置后开始操作

    任务59:垃圾回收机制

    Lua采用了自动内存管理机制

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    day01--计算机硬件基础笔记
    22 Jun 18 Django,ORM
    21 Jun 18 Django,ORM
    20 Jun 18 复习, mysql
    20 Jun 18 Django,ORM
    19 Jun 18 复习, 正则表达式
    19 Jun 18 Django
    15 Jun 18 复习, shutil模块
    15 Jun 18 Django
    14 Jun 18 复习, form表单
  • 原文地址:https://www.cnblogs.com/FudgeBear/p/8857795.html
Copyright © 2011-2022 走看看