zoukankan      html  css  js  c++  java
  • 第52天-lua语言基础语法

    Sublime 编辑器

    注意:在保存lua文件时,必须是<文件名.lua>的形式,必须加.lua后缀名

    执行脚本:Ctrl + B

    清空执行结果区:全选 + 删除

    Lua语句

    Lua语言是区分大小写的

    Lua语句不需要使用分号结尾, 但是即使写了分号也不保错

    Lua注释

    单行注释:-- (sublime快捷键:ctrl+/)

    多行注释: --[[ 语句 ]] (sublime快捷键:ctrl+shift+/)、--[[ 语句 ]]--、--[[ 语句 --]]

    --单行注释
    --print("11111111111")
    
    --多行注释
    --[[
    print("22222222222")
    
    print("33333333333333")
    ]]
    
    --[[
    print("22222222222")
    
    print("33333333333333")
    ]]--
    
    --[[
    print("22222222222")
    
    print("33333333333333")
    --]]
    多行注释推荐使用 --[=[注释内容]=]
    print("44444444444444444")

    Lua变量定义

    变量名 = 初始值

    无需指定数据类型, 会根据赋值的值自动改变变量的数据类型

    -- C#  数据类型  变量名 = 初始值
    c1 = [[abcdefg]]
    print(c1, type(c1))

    变量名(标识符)规范

    1、以字母或下划线开头

    2、后面可以有数字、字母、下划线组成

    3、尽量避免 下划线+大写字母 开头的写法,lua自身保留格式

    查看变量类型

    type(变量名)

    num = 10.1
    print(num, type(num))

    Lua数据类型

    number数字类型

    lua不区分整数与小数, 数都是number类型

    num = 10.1
    print(num, type(num))
    num2 = 10
    print(num2, type(num2))

    nil空数据

    等同于null

    nil可以使用在条件判断中,表示false结果

    boolean布尔类型

    ture 或者 false

    lua认为只有false和nil是假的(不满足条件), 其他都是真的(满足条件)

    string字符串类型

    Lua没有字符类型, 双引号与单引号都表示字符串类型

    "字符内容":不可以换行编辑

    '字符串内容':不可以换行编辑

    [[字符串内容]]:可以换行编辑,容易与多行注释冲突

    字符串的基本操作

    数学运算符 +、-、*、/、%

    当两个字符串进行数学运算符运算时,会将两个字符串转换成数值进行计算,如果转换失败就报错

    str1 = "5"
    str2 = "7"
    
    print("--------------------------字符的数学运算------------------------------")
    str3 = str1 + str2
    str4 = str1 - str2
    str5 = str1 * str2
    str6 = str1 / str2
    str7 = str1 % str2
    
    print(str3)
    print(str4)
    print(str5)
    print(str6)
    print(str7)

    字符串的连接

    使用“..” 两个点进行拼接

    print("-----------------------------字符串的连接-----------------------------")
    str8 = str1 .. str2
    print(str8)

    字符串的长度

    #变量名

    print("----------------------字符串的长度------------------------")
    
    str9 = "12345asgfasfd"
    length = #str9
    print(length)
    
    str10 = [[12345a
    sgfasfd]]
    length = #str10
    print(length)

    Lua运算符

    算术运算符

    +, -, *, /, %

    print(1 + 2)
    print(4 % 2)

    ^:幂次方

    2 ^ 3表示2的3次方

    print(2 ^ 3)

    关系运算符

    <,>,<=,>=,==,

    print(1 > 2)

    ~=:不等判断,与C#不一样

    print(1 ~= 2)

    逻辑运算符

    and:与

    同时为真才为真,相当于C# &&

    print(true and true)
    print(false and true)

    or:或

    只要有一个为真就为真,相当于C# ||

    print(false or true)

    not:非

    取反,相当于C# !

    print(not true)

    流程控制语句

    if 条件 then  语句  end

    --num为nil, lua认为nil为false
    if not num then
        print("num为nil")
    end
    
    year = 2004
    --1 能被4整除,不能被100整除
    --2 能被400整除
    if (year % 4 == 0 and year % 100 ~= 0) or year % 400 == 0 then
        print("year: "..year.." 是闰年")
    end

    if 条件 then  语句1 else 语句2 end

    -- if  else
    
    age = 19
    if age > 18 then
        print("你已经成年了")
    else
        print("你未成年")
    end

    if 条件1 then 语句1  elseif 条件2 then  语句2  else 语句3 end

    -- if  else if  else 
    --判断字符串是否是A或B ,如果是A打印 A1,如果是B打印B2, 如果都不是,打印C3
    str = "9"
    if str == "A" then
        print("A1")
    
    --elseif是放在一起写的,中间没有空格, 只要是条件判断,条件后要加then关键字
    elseif str == "B" then
        print("B2")
    else
        print("C3")
    end

    循环语句

    while

    --[[
    C# : 
    while(循环条件)
    {
        循环体
    }
    ]]
    
    --[[
    Lua:
    while 循环条件 do
        循环体
    end
    ]]
    num = 37
    --判断num是否是质数,  只能被1和本身整除的数就是质数
    print("判断num是否是质数,  只能被1和本身整除的数就是质数")
    isPrime = true
    i = 2
    while i < num do
        if num % i == 0 then
            isPrime = false
            --可以跳出
            break
        end
        i = i + 1
    end
    if isPrime then
        print("num: "..num .."是质数")
    else
        print("num: "..num .. "不是质数")
    end
    
    
    --打印100到999之间的水仙花数
    --153 = 1*1*1 + 5*5*5 + 3*3*3
    print("打印100到999之间的水仙花数")
    num = 100
    while num < 1000 do
        --取个位,十位,百位
        one = num % 10;
        tow = (num - one) / 10 % 10
        -- (153 - 3 - 5 * 10) / 100
        three = (num - one - tow * 10) / 100
        if one^3 + tow^3 + three^3 == num then
            print(num)
        end
        num = num + 1
    end

    repeat

    --[[
    C#:
    do
    {
        循环体
    }while(循环条件)
    满足条件循环
    ]]
    
    --[[
    lua:
    repeat
        循环体
    until 跳出循环条件
    满足条件退出循环
    ]]
    
    
    num = 10
    repeat
        print(num)
        num = num - 1
        --注意条件是跳出循环的条件
    until num >= 1

    for

    --[[
    C#
    for(int 变量 = 初始值; 循环条件; 增量表达式)
    {
        循环体
    }
    ]]
    
    --[[
    Lua
    
    for 变量 = 初始值, 阈值, 增量值 do
    
        循环体
    
    end 
    变量超过阈值,结束循环, 
    每次循环变量都增加增量值
    增量值可以省略,如果省略那么默认是1
    
    ]]
    
    --打印2到100之间的质数,包含2和100
    for num = 2,100 do
    
        isPrime = true
        for i = 2, num-1 do
            if num % i == 0 then
                isPrime = false
            end
        end
        if isPrime then
            print(num)
        end
    end
    
    
    --打印2000年到2050年之间的所有闰年
    for year = 2000, 2050 do
        if (year % 4 == 0 and year % 100 ~= 0) or year % 400 == 0 then
            print(year)
        end
    end

    注意:lua的循环语言可以使用break跳出,但是没有continue

    Lua中的数组

    lua  中没有数组的,是使用表table结构来模拟数组, 长度不是固定的

    lua数组的默认索引是从1开始的,不是从0,遇到非连续的索引后就停

    --[[
    C#
    数据类型[] 数组名 = new 数据类型[数组的长度]
    ]]
    
    --[[
    lua  中没有数组的,是使用表table结构来模拟数组, 长度不是固定的
    
    数据名 = {}
    ]]
    
    array1 = {}
    --可以初始化赋值
    array2 = {"123", "456"}
    
    --打印第1个数组元素
    print(array2[1])
    
    --数组的长度
    print(#array2)
    
    --遍历数组
    for i = 1, #array2 do
        print(array2[i])
    end
    
    --对第5个索引赋值为“789”
    array2[5] = "789"
    
    --数组的长度
    print("数组长度: "..#array2)
    
    --这种写法在语法上没有错误,但是主管不认为是数组
    array3 = {[-1] = "45678", [0] = "123", [1] = "456"}
    print(array3[-1])
    print(array3[0])
    
    --数组的长度
    print("数组长度: "..#array3)
    
    
    --将10 - 1 依次存储到一个数组中
    
    arr = {}
    
    index = 1
    for num = 10, 1, -1 do
        arr[index] = num
        index = index + 1
    end
    
    for i = 1, #arr do
        print(arr[i])
    end

    函数

    先定义,再执行

    -- 函数的定义
    --[[
    function 函数名(参数列表)
        
    end
    ]]
    
    --[[
    函数名 = function(参数列表)
        
    end
    ]]
    
    
    function Func1()
        print("执行Func1的方法")
        --该位置调用,只要保证Func1调用时在Func2定义之后就可以
        Func2()
    end
    
    --调用会报错, 因为Func2在该行执行时未定义
    --Func2()
    
    Func2 = function()
        print("Func2")
    end
    
    Func1()
    
    --带有参数与返回值的,注意参数列表无需指定类型
    function Func3(a, b)
        sum = a + b
        return sum
    end
    
    sum = Func3(10, 20)
    print(sum)
    
    
    --多个返回值
    function Func4()
        return 1, "str", true, {"abc", "def"}
    end
    
    --接收多个返回值的函数,要使用多个变量接收
    one, tow, three, four = Func4()
    print(one)
    print(tow)
    print(three)
    print(four[1])
    
    
    --lua函数还支持可变参数  ...
    function Func5(...)
        --通过数组获取可变参数
        --[[
        args = {...}
        for i = 1, #args do
            print(args[i])
        end
        ]]
    
        --第二种获取可变参数的方式, arg是lua方法中默认的可变参数组
        for i = 1, #arg do
            print(arg[i])
        end
    
        print("Func5")
    end
    
    Func5(1,"334", true, {"abc", "def"})

    表(table)

    lua中的table是一个关联数组, 索引可以是数字也可以是字符串

    --定义
    tab1 = {}
    tab2 = {[1] = "123", ["Key"] = 34, Name = "小明"}
    
    --赋值访问
    print(tab2[1])
    tab2["Name"] = "小李"
    tab2.Name = "小红"
    --访问字符串索引的元素
    print(tab2["Name"])
    print(tab2.Name)
    print(tab2["Key"])
    print(tab2.Key)
    
    -- 释放
    tab2 = nil
    
    print("----------------------------------------------------------")
    --表中存储方法
    tab3 = 
        { 
             Func1 = function(a)
                print("Func1: " .. type(a))
                print(a)
             end 
        }
    
    tab3.Func2 = function(a)
        print("Func2: " .. type(a))
    end
    
    --调用表中的方法
    --当使用:调用表中初始化时方法或通过表.方法名定义的方法时, 会将表作为第一个参数传递到方法中
    --当使用 . 调用表中初始化时方法或通过表.方法名定义的方法时, 不会将表传入
    tab3:Func1()
    print(tab3)
    tab3:Func2()
    
    print("=======================================================")
    function tab3:Func3(a)
        print("Func3: " .. type(a))
        print("self: " .. type(self))
    end
    
    --当调用使用 表:方法名 定义的方法时
    -- 表.方法()调用, 表示不传入当前表
    -- 表:方法()调用, 表示传入当前表, 不占参数位置,通过self可以获取表
    tab3:Func3()

    模块化开发

    require 函数

    require("<模块名>")

    TestModel引用其他文件

    --执行Model.lua的文件
    local m = require("Model")
    print("-----------------------------------------------------------------")
    
    print(m.Name)
    print(m.Age)
    m:Show()
    
    print("-----------------------------------------------------------------")
    --执行Model1.lua的文件, 注意Model1在当前文件文件夹的子文件夹Lesson下
    require("Lesson/Model1") -- Lesson/Model1 表示相对路径,相对于当前文件所在文件夹的路径
    
    --执行文件都有一个加载路径, 加载路径都存储在table表 package.path中
    --路径与路径间使用分号分隔,后缀是.lua,通过?来匹配文件名
    print(type(package.path))
    
    --执行Model3.lua的文件, 注意Model3在D盘的TestLua文件夹下
    --需要将桌面路径添加到 package.path 中,文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。
    package.path = package.path .. ";D:/TestLua/?.lua"
    
    require("Model3")
    
    print("========================================================================")
    tab = {"123", "234", "456", "567"}
    
    local Json = require("JsonUtility")
    --将表解析成Json串
    str = Json.encode(tab)
    print(str)

    Model

    print("Start Model ......")
    
    local Model = {}
    
    Model.Name = "小明"
    
    Model.Age = 18
    
    function Model:Show()
        print("我叫:" .. self.Name .. ", 我的年龄: " .. self.Age .. "")
    end
    
    return Model

    元表

    算术类

    +:__add

    --元表, 针对table的, 元表是改变表与表间的运算或操作的规则的
    
    t1 = {key = "123", age = 18}
    t2 = {name = "456", [-1] = "abc", [1] = "ghj", [2] = "fhgdsh", [4] = "asdfasdf"}
    
    add = 
    {
        --合并两个表为一个新的表
        __add = function (tab1, tab2)
            local tab = {}
            --遍历tab1
            for k,v in pairs(tab1) do
                tab[k] = v
            end
            --遍历tab2
            for k,v in pairs(tab2) do
                tab[k] = v
            end
            return tab
        end
    
    }
    
    --设置meta表为t1表的元表
    --setmetatable(t1, meta)
    setmetatable(t1, add)
    
    --当两个表向加运算时,先判断两个表是否有元表,如果都没有元表,直接报错
    --如果其中一个有元表,再判断元表中是否有 __add 的元方法,如果没有,直接报错
    --如果有元表并且有__add元方法, 那么执行__add的元方法, 该方法的返回值就是两个表相加的结果
    --执行__add元方法时,将 + 号左边的表作为第一个参数传入, 将+号右边的表作为第二个参数传入
    t3 = t1 + t2
    
    --print("t1", t1)
    --print("t2", t2)
    
    print(t3)
    
    for k,v in pairs(t3) do
        print(k,v)
    end

    -:__sub

    *:__mul

    /:__div

    比较类

    等于:__eq

    设置元表

    mytable = {}                          -- 普通表
    mymetatable = {}                      -- 元表
    setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表

    __index 元方法

    这是 metatable 最常用的键。

    当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。

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

    如果__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

    __newindex 元方法

    __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。

  • 相关阅读:
    13.Odoo产品分析 (二) – 商业板块(6) –采购(3)
    9.Odoo产品分析 (二) – 商业板块(4) –讨论(1)
    10.Odoo产品分析 (二) – 商业板块(5) –日历(1)
    8.Odoo产品分析 (二) – 商业板块(3) –CRM(2)
    7.Odoo产品分析 (二) – 商业板块(3) –CRM(1)
    the nearest point/vertex point of linestring
    Clojure的引用类型:var,ref,agent和atom
    clojure的delay future promise
    clojure的语法糖
    postgres select TOP X in group 查询每个组的前几名
  • 原文地址:https://www.cnblogs.com/yifengs/p/14544867.html
Copyright © 2011-2022 走看看