zoukankan      html  css  js  c++  java
  • 初识Lua

      前几天为了用xLua,学习了Lua语言,算是能用了...吧?(其实就只是跟着菜鸟教程过了一遍....)。但是感觉自己的记性一天不如一天(Orz),还是写个笔记好了,可能会对比着C++来。欢迎批评指正或者补充~

    一.基础(几乎语言都有的东西)

      1. 数据类型  

        Lua的数据类型很少,只有8种: nil、boolean、number、string、userdata、function、thread、table。

        nil 和C++里的 NULL 比较像,不过要注意的是,type(nil)~=nil 因为type()函数返回的是string。

        string 可以用 " ", ' ', [[ ]] 来包裹。其中[[ ]]一般包裹一整块的字符串。

        userdata 一般存储C/C++数据。

        function 用...来表示可变长参数,并且可以返回多个值。

        thread 我也只看了协程部分,见下文。

        table 是一个有点想法的数据结构。其组成是一个数组一个hash表(我都想要.jpg)。数组的扩张方法是*2(也就是说capacity永远是2^n)。

      2.语法词法

        特殊的算术运算符和关系运算符:幂运算是 ^ ,不等于是 ~= 。

        逻辑运算符:and,or,not

        长度运算符:# ,把它放在table或者string的前面,可以返回length。.. ,可以连接不同的字符串。

        除了 ^ 和 .. 外所有的二元运算符都是左连接的。

        if 语法和C++差不多,多了个then而已。

    1   if( 布尔表达式 1)
    2   then
    3      --[ 语句块 --]
    4   elseif( 布尔表达式 2)
    5   then
    6      --[ 语句块 --]
    7   else 
    8      --[ 语句块 --]
    9   end

             循环就有讲究了,分别为while,for,repeat三种

     1   while(condition)
     2   do
     3      statements
     4   end
     5   
     6   for var=from,to,step do  
     7       statements  
     8   end
     9   for i, v in ipairs(a) do
    10      statements
    11   end
    12   
    13   repeat
    14       statements
    15   until( condition )

          可以看到,其实while和repeat不过是一个在前一个在后,可以归为一种。for循环第一种就是普通用一个number(必须是number)作为控制变量进行循环,第二种则是用迭代器(见下文)进行循环。但是这个for循环很有意思,他是先判定循环几次,然后只运行那么多次的statements。也就是说像

    1   for i=1,10,1 do
    2       i=i-2
    3   end

    这种并不是死循环。

    二.特性(开始说一些特别的东西)

      1.迭代器

        lua里的迭代器实际上是三个变量:迭代函数不变量控制变量。像ipairs这种官方提供的函数也不过是包裹一下,返回这三个值而已。对于迭代函数来说,它需要返回两个值:控制变量新的值迭代出来的值(也就是我们实际获得的)。一旦有一次没有return,则停止迭代(待验证)。如:

      function iter(arg, index)
          index = index + 1
          print("index:", index)
          local v = arg[index]
          if(v and v~=100) then
              return index,v
          end
      end
      function foo(arg)
          for i,n in iter,arg,0 do
              print(n)
          end
      end
      local a = {["h"]=50, 20, 150, 100, 1566, [20]=6}
      foo(a)

        结果为

      index:    1
      20
      index:    2
      150
      index:    3

      2.元表

        由于元表这个东西不实际用,理解会很肤浅(没错就是我),大家将就着看吧......

        一个表可以有另一个表作为它的元表。我的理解是,表本身用作数据存放,元表则作为数据补充和方法实现。(所以可以把元表近似看作表本身的父表)

        表本身用作数据存放自不必说,而元表则作为数据补充体现在:若读写表本身时,表里没有其读写数据,则调用元表key为__index(读)和__newindex(写)的键值或函数。而方法实现体现在:

      运算符重载:
       key   对应运算符
      
      __add     +
      __sub     -
      __mul     *
      __div     /
      __mod     %
      __unm     -
      __concat  ..
      __eq      ==
      __lt      <
      __le      <=

    除了运算符重载(虽然不准确但就喜欢这么叫)外,还有__call和__tostring。前者在 Lua 调用一个值时调用,后者不多说。

      3.协程

        lua中每个协程都在一个单独的线程里。协程只有几个函数

      coroutine.create()    创建协程,返回thread对象,使用resume以重新执行协程
      coroutine.resume()    重新执行协程
      coroutine.yield()     挂起
      coroutine.status()    查看状态(dead,suspended,running)
      coroutine.wrap()     创建协程,返回function对象,调用函数为重新执行协程,其实质是非保护模式下的resume
      coroutine.running()   返回线程ID

        值得注意的,一个是create和wrap的区别,见上述。一个是yield和resume的配合。如:

      co = coroutine.create(
          function(a)
              print(a,"a[1]=",a[1])
              m = coroutine.yield(a)
              print(m,"m[1]=",m[1])
              m = coroutine.yield(m)
              print(m,"m[1]=",m[1])
              return a
          end
      )
    
      co2 = coroutine.create(
          function()
              print("co2", coroutine.running())
          end
      )
    
      f, c = coroutine.resume(co,{3,6})
      print(c,"c[1]=",c[1])
      s, c1 = coroutine.resume(co, {5,5})
      print(c,"c[1]=",c[1])
      print(c1,"c1[1]=",c1[1])
      coroutine.resume(co,{6,6})
      coroutine.resume(co)

        其结果为:

      table: 00559CA0    a[1]=    3
      table: 00559CA0    c[1]=    3
      table: 00559BD8    m[1]=    5
      table: 00559CA0    c[1]=    3
      table: 00559BD8    c1[1]=    5
      table: 00559D68    m[1]=    6

        由此可以看出:

      1. 首次调用resume执行协程co时,参数 会赋值给协程的函数,作为函数参数
      2. yeild的参数会作为resume的第二个返回值(第一个是boolean表示是否成功)
      3. 再调用resume执行协程co时,参数 会赋值给协程上一次yield的返回值
      4. 循环2、3直到return

        4.垃圾回收

          这就没细看了,就列个表以后忘了回来查吧。

      collectgarbage("collect"): 做一次完整的垃圾收集循环。通过参数 opt 它提供了一组不同的功能:
    
      collectgarbage("count"):以 K 字节数为单位返回 Lua 使用的总内存数.这个值有小数部分,所以只需要乘上1024就能得到Lua使用的准确字节数(除非溢出)
    
      collectgarbage("restart"): 重启垃圾收集器的自动运行。
    
      collectgarbage("setpause"): 将 arg 设为收集器的 间歇率。 返回 间歇率 的前一个值。
    
      collectgarbage("setstepmul"): 返回 步进倍率 的前一个值。
    
      collectgarbage("step"): 单步运行垃圾收集器。 步长"大小"由arg控制。传入0时,收集器步进(不可分割的)一步。传入非0值,收集器收集相当于Lua分配这些多(K字节内存的工作。如果收集器结束一个循环将返回true 。
    
      collectgarbage("stop"): 停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。

        5.其他(写一些杂七杂八)

           : 和 . 的区别:table:function(args...)是一个语法糖, 其实质为table.function(self,args...)并自动传参self。

  • 相关阅读:
    阅读《构建之法》
    准备工作
    课程总结
    第十四周总结
    第十三周总结
    Flex撑开
    多行文本展示为省略号样式的react组件
    如何在Spring Boot 中动态设定与执行定时任务
    System.arraycopy() 和 Arrays.copyOf() 的区别说明
    使用反射机制,获取 ArrayList 的容量大小
  • 原文地址:https://www.cnblogs.com/charsoul/p/11144932.html
Copyright © 2011-2022 走看看