***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
学习lua啦~
首先,一把好的武器——sublime,
相关 安装配置 传送门—— >here<
本篇博文主要内容有:
> lua的基本类型
> lua的 table
> lua的 function
先来一段lua的介绍吧:
首先 lua 是一个脚本语言(何为脚本语言?——看下面注释①),lua由标准C编写而成,所以它与C的交互非常好,比较容易的进行互相的调用,也很容易在各个平台进行编译,最关键的是它非常的"轻",整个压缩包,也就200多K。
在游戏开发中,用lua就很方便,在发布一个游戏后,发现个大BUG,如果按编译型语言的方法,你就需要去重新编译打包,巴拉巴拉~,黄花菜都凉了,用lua就很方便,修改好,覆盖原来的,当你重新登陆时,就用已经改好的了。对用户对开发都很方便。
所以,一起来学lua吧~。~
1. lua的基本类型
- - -在lua中,有8种基本类型,分别是
· nil 空类型 · number 数字类型,不分int or float or double,双精度浮点 · string 字符串类型,无法具体的更改某个位置的字符,只能整块整块操作 · boolean 布尔类型(只有nil与false 为假,其他都为真) · function 函数类型(☆第一类值☆),非常重要,后面会细讲 · table 表类型,也很重要后面会细讲 · userdata <span style="white-space:pre"> </span>自定义类型 · thread 线程类型
我们可以用type来判断一个变量的类型:
-- 判断变量的类型 function judgeType( val ) if type(val)=="number" then print("类型是 number") elseif type(val)=="nil" then print("类型是 nil") elseif type(val)=="string" then print("类型是 string") elseif type(val)=="function" then print("类型是 function") elseif type(val)=="boolean" then print("类型是 boolean") elseif type(val)=="table" then print("类型是 table") end end local myInt = 3 local myFloat = 4.375 local myStr = "Hello Lua!" local myFunc = function () end local myBoolean = true local myNil = nil local myTable = {} print("myInt") judgeType(myInt) print("myFloat") judgeType(myFloat) print("myStr") judgeType(myStr) print("myFunc") judgeType(myFunc) print("myBoolean") judgeType(myBoolean) print("myNil") judgeType(myNil) print("myTable") judgeType(myTable)
会输出:
2. lua 的 table
- - - table,上面也说到了 表类型,在lua中 table既不是值 也不是变量,而是 对象。
首先,看一下,最简单的 table:
t = {}
我们可以用 数字、字符串、变量 来索引内容,也可以随时动态的添加内容。
(但是,虽然我们可以用任意值作为table的索引,但是当table作为数组时,默认还是从1开始的。)
t = {} t[1] = 3 t["haha"] = "heihei" local x = "haha" print(t[1]) print(t["haha"]) print(t[x])
3 heihei heihei
k = t k[x] = "hello" print(t.haha)
hello
这里 我用到了t.haha,table后跟着 .xxx 等同于 table["xxx"]
当我们 将 t 与 k 都置为nil时,lua垃圾回收机制才会将 这些内容 释放。
就是,我们创建一个table,就是在划分一个空间创建它,然后在 这块 与变量名间 做个引用关系,如果有复制,就一直加一些引用,而不是创造一个新的副本,最后就是 一个table 外面牵着很多引用,当所有的引用都断开,lua的回收机制就会收了它~
3. lua 的 function
lua中非常重要的一个东西 —— 第一类值,
啥意思呢,它是一个函数,但是可以作为变量,可以当参数,可以当返回值,可以...
- - - 它的形式:
function 函数名( 参数列表 ) 函数体 end
函数声明可以是这两种形式:
function function_name( ... ) -- body end local fun = function ( ... ) -- body end
但是,这两种还是有所区别的,看看下面这种情况
function sum( n ) if n < 0 then return 1 else return sum(n-1) end end local ssum = function ( n ) if n < 0 then return 1 else return ssum(n-1) end end print(sum(4)) print(ssum(4))
但是,这两种样子还是有所区别的
第二种ssum在编译时会报错——视图调用一个空值 ssum
第一种写法: 声明一个函数sum,并开始定义,然后可以直接调用。
第二种写法: 声明一个函数(匿名函数),开始定义,这时候还没赋值给 ssum,所以ssum是空值,所以会报错。
还是那句话——function 是第一类值!!
在函数的声明中,当参数只有一个,而且参数是 table类型或者string类型 的时候,它就可以省略掉括号,
print("hello lua!") 等价于 print "hello lua!" fun({x=1,y=2}) 等价于 fun {x=1,y=2}
- - - 函数的返回值,function支持 多重返回值,直接return就行
-- 函数的返回值 function add( val1 ,val2 ) return val1,val2,val1+val2 end local q1,q2,ans = add( 2, 3 ) print(q1.." + "..q2.." = "..ans)
但是,函数的多重返回值也有一些规则,有些时候,返回的一些数据会被扔掉,这主要取决于 函数的位置
-- 函数的多重返回值 function demo( ) return 1, 2 end local a, b, c = 0, 0, 0 a, b, c = demo(), 5 print(a.." "..b.." "..c) -- 输出:1 5 nil a, b, c = 0, 0, 0 a, b, c = 5, demo() print(a.." "..b.." "..c) -- 输出:5 1 2 a, b, c = 0, 0, 0 a, b, c = 5, (demo()) print(a.." "..b.." "..c) -- 输出:5 1 nil
- - - function的变长参数,像函数内传入的参数个数是可变的
-- 变长参数 function sum( ... ) print( "length is :" .. select('#', ...) ) local s = 0 for i, v in ipairs{...} do s = s + v end return s end print( sum(1,2,3,4,5) ) print( sum(3,3,4) )
这里也用到了 select('#',...) 用来 查参数长度, ...可以拿来当做表达式来用。
- - - 函数闭包 问题
function Counter() local count = 0 return function () count = count + 1 return count end end local c = Counter() print( c() ) print( c() ) local c2 = Counter() print( c2() ) print( c() ) print( c2() )
当你 编译,之前两个 print,会输出 1 2
这就是典型的闭包,但,当你以为 闭包 是函数公用变量时,再看看 下面三个 print,输出:1 3 2
所以,闭包,并不仅仅的是让函数内的某个变量一直保存,感觉像静态变量一样。
而是,对于每一个 引用该函数的 变量,它就会有一个闭包。
这应该怎么去理解呢?
—— 答案就在 那一句 function是第一类值,你把它当做一个变量,然后分析一下作用域,就发现很容易去接受理解了。
- - - 非全局函数
因为 函数是第一类值,所以它可以在table中存在
-- 非全局函数 t = {} t.add = function (x, y) return x + y end t.sub = function (x, y) return x - y end local a, b = 3, 4 print(t.add(3,4)) print(t.sub(3,4))
还有其他写法:
t = { add = function (x, y) return x + y end sub = function (x, y) return x - y end } t = {} function t.add (x, y) return x + y end function t.sub (x, y) return x - y end
把函数放到局部变量中,它就只能在特定的作用域发挥作用,这点对于我们编程来说是比较有用的。
- - - 尾调用
尾调用,就是类似于 goto函数的调用,就是一个函数的最后一个动作是调用另一个函数。
function f(x) return g(x) end
可以发现,当我们执行到 最后一个动作——调用g函数后,返回到 f函数,也没有什么事情可以做,所以,我们可以不返回到f函数。
要知道,这么开销下去,都是放在栈中,很可能导致栈溢出的。
会使用尾调用消除,就应该先看程序是怎么判断它是尾调用的:
-- 1 function f( x ) g(x) end -- 2 function f( x ) return g(x) + 1 end -- 3 function f( x ) return x or g(x) end -- 4 function f( x ) return (g(x)) end -- 5 function f( x ) return x[i].foo(x[j]+a*b , i+j) end
上面的这些,除了第5个,都不是尾调用,
先说第一个,和例子有些像,但是 f函数在 调用完g函数后,并不能立即返回,它还要负责将g函数返回的结果丢弃。
后面的,都要对g函数返回的结果进行处理 再返回。(其实第一个也是进行了处理)
所以,要想安心用这个功能,那就好好的return吧。
注释:
① 脚本语言:是为了缩短传统的 编写-编译-链接-运行 过程而创建的一种计算机语言,一个脚本语言通常是进行 解释而非编译。它的优势在于可以 快速开发,容易部署,不必耗时编译/打包,可以嵌入到别的语言中,利用其它语言的库,而且易学易用,可以实时生成和执行。
② 语法糖:在语言中添加某种语法,对功能没有什么影响,但是会便于程序员调用,增加代码可读性,减少出错机会。
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************