深入浅出Lua编程实战视频课程:(1)

默认教学计划
32人加入学习
(1人评价)
价格 ¥59.00
教学计划
承诺服务
会员免费学 购买课程

--生产者
produceFunc = function()
while true do
local value = io.read()
print("produce: ",value)
coroutine.yield(value) --返回生产的值
end
end
--消费者
consumer = function(p)
while true do
local status, value = coroutine.resume(p); --唤醒生产者进行生产
print("consume: ",value)
end
end
 
--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
consumer(producer)
输入1,打印1
1
produce: 1
consume: 1
输入2,打印2
2
produce: 2
consume: 2
 

[展开全文]

 
协程库
(1)coroutine.create(f)
传一个函数参数,用来创建协程。返回一个 “thread”对象
(2)coroutine.status(co)
返回一个字符串,表示协程的状态。有4种状态:
1)、running。如果在协程的函数中调用status,传入协程自身的句柄,那么执行到这里的时候才会返回 running 状态。
2)、suspended。如果协程还未结束,即自身调用了 yield 或还没开始运行,那么就是 suspended 状态。
3、dead。如果一个协程发生错误结束,或正常终止。那么就处于 dead 状态。如果这时候对它调用 resume,将返回 false 和错误消息。
 
 
 
协程库
(3)coroutine.resume(co [,val1, ...])
这是一个非常重要的函数。用来启动或再次启动一个协程,使其由挂起状态变成运行状态。
可以这么说,resume 函数相当于在执行协程中的方法。参数 Val1... 是执行协程 co 时传递给协程的方法。
首次执行协程co时,参数Val1...会传递给协程co的函数;
再次执行协程co时,参数Val1... 会作为给协程co中上一次yield的返回值。
不知道这句话大家理解了没,这是协程的核心。
resume 函数返回什么呢?有3种情况:
1)、如果协程co的函数执行完毕,协程正常终止,resume 返回 true和函数的返回值。
2)、如果协程co的函数执行过程中,协程让出了(调用了yield()方法),那么resume返回true和协程中调用yield传入的参数。
3)、如果协程co的函数执行过程中发生错误,resume返回false与错误信息。
可以看到resume无论如何都不会导致程序崩溃。他是在保护模式下执行的。
 
协程库
(7)coroutine.yield(...)
使正在执行的函数挂起。
传递给yield的参数会作为resume的额外返回值。
 
同时,如果对该协程不是第一次执行resume,resume函数传入的参数将会作为yield的返回值。
 
function f(a,b)
print("hello world");
print(a,b)
end
 
co = coroutine.create(f);
print(coroutine.status(co));
coroutine.resume(co,1,2);
suspended
hello world
1 2
>Exit code : 0
 
function f(a,b)
print("hello world");
c,d = coroutine.yield();
print(c,d);
--print(a,b);
end
 
co = coroutine.create(f);
print(coroutine.status(co));
coroutine.resume(co,1,2);
coroutine.resume(co,100,200);
suspended
hello world
100 200
>Exit code: 0
 
function f(a,b)
print("hello world");
return 200;
end
 
co = coroutine.create(f);
print(coroutine.status(co));
c,d = coroutine.resume(co,1,2);
print(c,d);
suspended
hello world
true 200
>Exit code: 0
 
 
function f(a,b)
print("hello world");
coroutine.yield(1000);
end
 
co = coroutine.create(f);
c,d = coroutine.resume(co,1,2);
print(c,d);
hello world
true 1000
>Exit code: 0
 
协程库
 

[展开全文]

协程概念
一、协程是什么?
(1)线程
首先复习一下多线程。每一个线程都代表一个执行序列。
当我们在程序中创建多线程的时候,同一时刻多个线程是同时执行的,如果只有一个 CPU,同一个时刻只有一个线程在执行。在一个时间片内执行那个线程是不确定的,我们可以控制线程的优先级,不过真正的线程调度由 CPU 的调度决定。
(2)协程
那什么是协程呢?协程跟线程都代表一个执行序列。不同的是,协程把线程中不确定的地方尽可能的去掉,执行序列间的切换不再由 CPU 隐藏的进行,而是由程序显式的进行。
 
协程状态
create→ 挂起 resume→ 运行→死亡
←yield
 
function f()
print("hello world");
print(coroutine.status(co));--打印协程的状态
end
 
co = coroutine.create(f);
 
function f()
print("hello world");
end
 
co = coroutine.create(f);
print(coroutine.status(co));
suspended
>Exit code: 0
 
suspended 暂停状态
 
function f()
print("hello world");
end
 
co = coroutine.create(f);
print(coroutine.status(co));
coroutine.resume(co); --运行协程
 
function f()
print("hello world");
print(coroutine.status(co));
end
 
co = coroutine.create(f);
print(coroutine.status(co));
coroutine.resume(co);
 
suspended
hello world
running
>Exit code: 0
 
function f()
print("hello world");
print(coroutine.status(co));
end
co = coroutine.create(f);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
 
suspended
hello world
running
dead
>Exit code: 0
 

[展开全文]

xpcall 函数
xpcall(f, msgh [,arg1,...]) xpcall
类似 pcall xpcall 接受两个参数:调用函数、错误处理函数
 
错误处理函数
function test(i)
error("error ...");
end
 
function error()
print(debug.traceback());
end
 
xpcall(test,error,33);
 
function test(i)
errot("error....");
end
 
function errorFun()
print(debug.traceback());
end
 
xpcall(test,errorFun,30);
stack traceback:
1.lua:6: in function <1.lua:5>
[C]; in function 'error'
1.lua:2: in function <1.lua:1>
[C]: in function 'xpcall'
1.lua:9: in main chunk
[C]: ?
>Exit code: 0
 
debug.traceback() 调用堆栈信息

[展开全文]

function add(a,b)
 
assert(tonumber(a),"a is not number");
assert(tonumber(b),"b is not number");
 
return a+b;
end
 
print(add("abc",200));
print(1000);
 
lua: 1.lua:3 a is not number
stack traceback:
[C]: in function 'assert'
1.lua:3: in function 'add'
1.lua:9: in main chunk
[C]: ?
>Exit code: 1
 
错误处理
 
pcall
 
pcall 类似其他语言里的 try-catch,使用 pcall 调用函数,如果函数 f 中发生了错误,
它并不会抛出一个错误,而是返回错误的状态,为被执行函数提供一个保护模式,保证程序不会意外终止。
 
语法
 
pcall( f , arg1 , ...)
返回值
1.函数执行状态(boolean)
没有错误返回 true
有错误返回 false
2.发生错误返回错误信息,否则返回函数调用返回值
 
function add(a,b)
assert(tonumber(a),"a is not number");
assert(tonumber(b),"b is not number");
return a+b;
end
--print(add("abc",200));
pcall(add,"abc",200);
print(1000);
1000
>Exit code: 0
 
function add(a,b)
assert(tonumber(a),"a is not number");
assert(tonumber(b),"b is not number");
return a+b;
end
--print(add("abc",200));
local state,val = pcall(add,"abc",200);
print(state,val);
print(1000);
false 1.lua:3: a is not number
1000
>Exit code: 0
 
function add(a,b)
assert(tonumber(a),"a is not number");
assert(tonumber(b),"b is not number");
return a+b;
end
--print(add("abc",200));
local state,val = pcall(add,100,200);
print(state,val);
print(1000);
true 300
1000
>Exit code: 0
 
错误处理
例子求两个数之和
function add(a,b)
return a+b;
end
local status,err = pcall(add,"add",200)
if status then
print(status);
else
print(err);
end
 

[展开全文]

错误处理
例子:求两个数之和
function add(a,b)
return a+b;
end
 
function add(a,b)
return a+b;
end
 
print(add(100,200));
300
>Exit code:0
 
function add(a,b)
return a+b;
end
 
print(add("abc",200));
 
lua:1.lua:2: attempt to perform arithmetic on local 'a' (a string value)
stack traceback:
1.lua:2: in function 'add'
1.lua:5: in main chunk
>Exit code: 1
 
function add(a,b)
return a+b;
end
 
print(add({10,20,30},200));
lua: 1.lua:2: attempt to perform arithmetic on local 'a' (a table value)
stack traceback:
1.lua:2: in function 'add'
1.lua:5: in main chunk
[C]; ?
 
function add(a,b)
if(tonumber(a) == nil or tonumber(a) == false) then
print("a is not number");
return;
end
 
if(tonumber(b) == nil or tonumber(b) == false) then
print("b is not number);
return;
end
 
return a+b;
end
 
print(add({10,20,30},200));
 
a is not number
>Exit code:0
 
错误处理
例子求两个数之和
function add(a,b)
if type(a) == "number" adn type(b) == "number" then
return a+b;
else
error("input invalid");
end
end
 
错误处理
例子求两个数之和
function add(a,b)
a=assert(tonumber(a),"invalid input a");
b=assert(tonumber(b),"invalid input b");
return a+b;
end
 
错误处理
assert()##
原型:assert(v [,message])
解释:当参数v的值是false或者nil的时候展示一个错误,否则返回参数值。其中参数message表示一个错误信息,这个参数的默认值是assertion failed!
 
function add(a,b)
 
assert(tonumber(a),"a is not number");
assert(tonumber(b),"b is not number");
 
return a+b;
end
 
print (add("abc",200));
lua: 1.lua:3: a is not number
stack traceback:
[C]: in function 'assert'
1.lua:3: in function 'add'
1.lua:9: in main chunk
[C]: ?
>Exit code: 1
 

[展开全文]

dofile("text.lua")
 
source.lua
for i=1,10,1 do
print(i);
end
 
test.lua
dofile("e:/lua/lesson/7-1/source.lua")
 
test.lua
f = loadfile("e;/lua/lesson/7-1/sources.lua");
f();
 
f1=loadstring("print(10)");
f1();
 
 

[展开全文]

迭代器应用
打印一个文本文件里的所有单词。
找到文件里所有的行的内容
在每一行里找到所有的单词
 
function parseLine(line)
local pos=1;
local s,e;
while true do
s,e=string.fine(line,"%w+",pos);
if s then
pos=e+1;
print(string.sub(line,s,e));
else
break;
end
end
end
 
for line in io.lines("E:/lua/lesson/les6-4/test.txt") do
parseLine(line);
end
 
 
 
 
 
 
local iterator;
 
function allwords()
local state {line=io.read(),pos=1}
return iterator,state;
end
 
function iterator(state)
while state.line do
local s,e=string.fine(state.line,"%w+",state.pos);
if s then
state.pos=e+1;
return string.sub(state.line,s,e);
else
state.line=io.read();
state.pos=1;
end
end
return nil;
end
 
file=io.open("E:/lua/lesson/les6-4/test.txt","r");
io.input(file);
 
for word in allwords() do
print(word);
end
 
 

[展开全文]

function iter(t,i)
i=i+1;
if(t[i]~=nil) then
return i,t[i];
end
end
 
function values(t)
return iter,t,0;
end
 
t={10,20,30}
for i,v in values(t) do
print(v);
end
 
iter(t,i) 称为无状态迭代器

[展开全文]

迭代器与闭包
function values(t)
local i = 0;
return function()
i=i+1;
return t[i];
end
end
t={10,20,30}
for element in values(t) do
print(element);
end
 
泛型for语义
for <var-list> in <exp-list> do
block
end
 
var-list 是一个或多个变量列表,以逗号分开;exp-list 是一个或多个表达式列表,同样以逗号分开,通常只有一个元素,即迭代器工厂的调用。
 
 
泛型for
for k,v in pairs(t) do
print(k,v)
end
 
for line in io.lines() do
io.write(line,"\n");
end
 
泛型for语义
for <var-list> in <exp-list> do
block
end
 
do
local _f,_s,_var = <explist>;
while true do
local var_1,...,var_n=_f(_s,_var);
_var=var1;
if _var==nil then break end
<block>
end
end
 

[展开全文]

闭包与迭代器
举例:打印一个表里的元素。
t={10,20,30}
for i=1,#t,1 do
print(t[i]);
end
闭包与迭代器
function values(t)
local i=0;
return function()
i=i+1;
return t[i];
end
end
 
t={10,20,30}
iter=values(t)
while true do
local element=iter();
if element==nil then break end
print(element)
end
 
fuunction values(t)
local i=0;
return function()
i=i+1;
return t[i];
end
end
 
t={10,20,30}
iter=values(t);
a=iter();
b=iter();
print(a);
print(b);
 
 
 
 
闭包与迭代器
iter称为迭代器
生成迭代器的函数称为迭代工厂
for in 语句称为泛型for语句
 
function values(t)
local i=0;
return function()
i=i+1;
return t[i];
end
end
t={10,20,30}
for v in values(t) do
pint(v);
end
 

[展开全文]

函数调用
 
尾调用
定义
当一个函数是另外一个函数的最后一个动作时,该调用才称为尾调用
function g()
block
return 1;
end
function f()
return g();
end
f();
 
尾调用
function g(x)
block
end
 
function f(x)
return g(x) + 1;
end
因为最后一个动作是 + 1,这个调用不是尾调用
 
尾调用
尾调用不需要获取堆栈信息,相当于goto直接跳转
 
尾调用
举例:求 1*2*3*...*n
function f(n)
if n<=1 then
return 1
end
a = f(n-1)
 
return n*a
end
 
function f(n,now)
if n<=1 then
return now
end
return f(n-1,now*n)
end
 
堆栈错误
 
function f1(n,now)
if n<=1 then
renturn now;
end
return f1(n-1,now*n);
end
 
prrint(f1(30000,1));
尾调用不需要堆栈信息

[展开全文]

非全局函数
//举例:实现1*2*3*...*n
 
第一种:
local function fact(n)
if(n==0) then return 1;
else return n*fact(n-1);
end
 
第二种:
local fact;
fact = function(n)
if(n==0) then return 1;
else retun n*fact(n-1);
end
 
(错误)
local fact = function(n)
if(n==0) then return 1;
else return n*fact(n-1);
end

[展开全文]

词法域
例子:将名字按照年纪从大到小排列
names = {"Peter","Paul","Mary"}
grades = {Mary = 10,Paul = 7,Peter = 8}
 
table.sort(names,function(n1,n2)
return gardes[n1] > grades[n2]
end);
table.sort(table [,comp])
 
词法域
names = {"Peter","Paul","Mary"}
grades = {Mary = 10,Paul = 7,Peter = 8}
 
function sortbygrade(t1,t2)
table.sort(t1,function(n1,n2)
return t2[n1] > t2[n2];
end)
end
匿名函数访问了外部函数sortgrade的局部参数t2,t2不是全局变量,它也不是匿名函数的局部变量,这样的变量称为“非局部变量”(UpValue),lua允许内部函数访问外部函数中的局部变量,这项特征称为“词法域”
闭包
 
闭合函数
闭包的概念
在Lua中,闭包(closure)是由一个函数和该函数会访问到的非局部变量(或者是upvalue)组成的,其中非局部变量(non-local variable)是指不是在局部作用范围内定义的一个变量,但同时又不是一个全局变量,主要应用在嵌套函数和匿名函数里,因此若一个闭包没有会访问的非局部变量,那么它就是通常说的函数。也就是说,在Lua中,函数是闭包一种特殊情况。
 
第一类值
第一类值
把可以存放在变量,可以作为函数参数,也可以作为返回值的类型称为第一类值(boolean,number),在lua里函数是第一类值。
第二类值
把不可以存放在变量里,不可以作为函数参数,也不可以作为返回值的类型称为第二类值。
 
第一类值
function add(a,b)
return a+b;
end
 
local f = add;
local s = f(100,200);
 
函数参数
 
返回函数
function test()
local i = 0;
return function()
i = i+ 1;
return i;
end
end
 
f = test();
local a = f(); print(a);
local b = f(); print(b);
 
f1 = test();
local c = f1(); print(c)
 
 
 
 
 
 

[展开全文]

变长参数函数
function add(...)
local sum = 0;
local t = {...};
 
for i = 1, #t,1 do
sum=sum+t[i];
end
 
return sum;
end

变长参数
function add(...)
local sum = 0;
for i = 1, select('#',...), 1 do
sum = sum + select(i,...);
end
return sum;
end
select('#',...),表示参数个数
local a = select(i,...),第i个元素

[展开全文]

多重返回值
//求一个数组中最小元素值及元素位置。
function min(a)
local idx = -1;
local min = math.huge();
for i,v in ipairs(a) do
if v<min then
min = v;
idx = i;
end
end
return i,min;
end
 
多重返回值
Lua 会调整一个函数的返回值数量以适应不同的调用情况。
1.如果将函数作为一条单独语句时,Lua 会丢弃函数的所有返回值。
2.只有当函数调用是一系列表达式中的最后一个元素(或者仅有一个),才能获得它的所有返回值。
3.如果将函数作为表达式的一部分调用时,Lua 只返回函数的第一个返回值。
 
 
多重返回值
1.如果将函数作为一条单独语句时,Lua 会丢弃函数的所有返回值。
function foo0() end --无返回值
function foo1() return "a" end; --1个返回值
function foo2() return "a","b" end
 
foo();
foo1();
foo2();
多重返回值
2.只有当函数调用是一系列表达式中的最后一个元素(或者仅有一个),才能获得它的所有返回值。
function foo0() end --无返回值
function foo1() return "a" end; --1个返回值
function foo2() return "a","b" end
 
x,y = foo2(); --x = "a", y = "b"
x,y,z = 10,foo2(); --x = 10, y = "a", z = "b"
t = {foo2()} --t[1] = "a", t[2] = "b"
多重返回值
3.如果将函数作为表达式的一部分调用时,Lua 只返回函数的第一个返回值。
function foo0() end --无返回值
function foo1() return "a" end; --1个返回值
function foo2() return "a","b" end
 
x,y = foo2(),20 --x = "a", y = 20;
t = {foo0(),foo2(),4} -- t[1] = nil, t[2] = "a", t[3] = 4;
 

[展开全文]

函数定义

function 函数名(形参列表)

函数体

end

 

//求一个数组中最小元素值

function min(t)

local minv = math.huge;

for l,v in ipairs(t) do

if v < minv then

minv = v;

end

end

return minv;

end

 

函数调用

 

 

 

_G.min

 

 

加了 local 的函数

 

函数调用

在函数调用时只有一个参数时,并且此参数是一个字符串或者table构造式,括号是可有可无

min {1,2,3,4,5)

 

 

[展开全文]

循环语句

例子:

打印数组days的元素

days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}

 

for k = 1,#day,1 do

print(days[k])

end

#days 表示数组的长度,也可以用 table.getn()

 

循环语句

例子:

打印数组days的元素

days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday",x="aa",y="bb"}

 

for k = 1,#day,1 do

print(days[k])

end

 

只打印了数组中元素,没有“aa”和“bb”

 

泛型for

for 参数列表 in 泛型函数 do

block

end

泛型函数:

ipairs是遍历数组的泛型函数,第一个参数被赋值一个索引,第二个参数被赋予一个对应于该索引的值。

for i,v in ipairs(t) do

block

end

 

for i,v in ipairs(days) do

print(v);

end

 

泛型for

pairs是迭代表中所有元素的泛型函数。第一个参数被赋予key值,第二个参数被赋予value值。

 

for k,v in pairs(t) do

blcok

emd

 

io.lines 迭代文件中的所有行。

 

for k,v in pairs(days) do

print(k,v)

end

 

 

for k in io.lines("E:\\lua\\lesson\\les4-6\\1.txt") do

print(k);

end

 

 

[展开全文]

while 语句

例子

求100以内奇数和

1+3+5+...+99

 

break 语句

在执行代码块时,如果希望完全结束一个循环,跳出循环体执行循环后面的语句,可以使用break语句。

 

例子:

实现要求用户输入用户名、密码,只要不是admin和888888就一直提示要求重新输入

读取用户输入:io.read()

io.read() 中保存的类型是 string 类型

 

 

 

 

 

[展开全文]

循环语句

while 循环

for 循环

repeat...until

 

while 语句

while 条件 do

代码块

end

while 条件,条件为假时,退出循环

 

 

 

 

for 语句

for 变量=初值,循环结束值,步长 do

代码块

end

 

 

 

 

repeated 语句

repeat

代码块

until 结束条件

结束条件为真时,退出循环

 

--打印小于100的整数

local i = 1;

repeat

print(i);

i = i + 1;

until i > 100

 

 

[展开全文]

授课教师

泰课高级讲师

课程特色

视频(39)

学员动态

shingling 加入学习
知足 完成了 8-2协程库
知足 开始学习 8-2协程库