第六章 深入理解函数 Lua程序设计笔记

--第六章 深入理解函数
Lua中函数是“第一类值”,与其他传统类型有相同的权利:
可以储存到变量或table中,可以作为函数实参传递,还可以作为函数的返回值。

函数的标准定义:

foo = function(x) return x*2 end

一个函数定义实际上就是一条赋值语句,这条语句创建了一种类型为“函数”的值,并将这个值赋予一个变量。

--6.1closure(闭合函数)

function newCounter()
local i = 0
return function()
        i = i + 1
        return i
    end
end

非局部的变量(non-local variable):
是外部函数的局部变量,在内部的匿名函数中,既不是局部也不是全局变量。如上面的i。
一个closure就是一个函数加上该函数所需访问的所有“非局部的变量”。
c1和c2是同一个函数创建的两个不同的closure,它们各自拥有局部变量i的独立实例。

c1 = newCounter()
print(c1()) -->1
print(c1()) -->2
c2 = newCounter()
print(c2()) -->1
print(c1()) -->3
print(c2()) -->2

--6.2非全局函数
一个错误的示例:

local fact = function(n)
    if n == 0 then return 1
    else return n * fact(n-1)
    end
end

当编译到函数体中调用fact(n-1)时,由于局部fact尚未定义完毕,因此这个语句其实调用了一个全局的fact。

正确的写法:

local fact
fact = function(n)
    if n == 0 then return 1
    else return n * fact(n-1)
    end
end

现在函数中的fact调用就表示局部变量。

使用语法糖

local function foo() <body> end

Lua将其展开为:

local foo
foo = function() <body> end

因此使用语法糖可以直接定义递归:

local function fact(n)
    if n == 0 then return 1
    else return n*fact(n-1)
    end
end

但是对于间接递归,必须使用明确的前向声明(forward declaration)

local f,g
function g()
    ... f() ...
end
function f()
    ... g() ...
end

--6.3正确的尾调用(tail call)
当一个函数调用的是另一个函数的最后动作是,才是一条尾调用:

function f(x) return g(x) end

不是尾调用的示例:

function f(x) g(x) end --调用完g后,f并不能立即返回,而还需要丢弃g返回的临时结果
return g(x) + 1   --还要做一个加法
return x or g(x)  --还要调整为一个返回值
return (g(x))     --还要调整为一个返回值

一个尾调用就好比一个goto语句,迷宫游戏的案例:

function room1()
    local move = io.read()
    if move == "south" then return room3()
    elseif move == "east" then return room2()
    else print("invalid move") return room1()
    end
end
function room2()
    local move = io.read()
    if move == "south" then return room4()
    elseif move == "west" then return room1()
    else print("invalid move") return room2()
    end
end
function room3()
    local move = io.read()
    if move == "north" then return room1()
    elseif move == "east" then return room4()
    else print("invalid move") return room3()
    end
end
function room4()
    print("congratulations!")
end

通过调用room1()进入游戏

时间: 2024-10-17 22:05:34

第六章 深入理解函数 Lua程序设计笔记的相关文章

第五章 函数 Lua程序设计笔记

--第五章 函数若函数只有一个参数,并且此参数时字符串或table,则圆括号可有可无 print "hello world" <--> print("hello world") f {x = 10, y = 20} <--> f ({x = 10, y = 20}) --5.1多重返回值 function foo0 () end function foo1 () return "a" end function foo2 (

[深入理解Android卷二 全文-第六章]深入理解ActivityManagerService

由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容 第6章 深入理解ActivityManagerService 本章主要内容: ·  详细分析ActivityManagerService 本章所涉及的源代码文件名及位置: ·  SystemServer.java frameworks/base/services/java/com/android/server/

《深入理解Android 卷III》第六章 深入理解控件(ViewRoot)系统

<深入理解Android 卷III>即将公布,作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分. 在一个特别讲究颜值的时代,本书分析了Android 4.2中WindowManagerService.ViewRoot.Input系统.StatusBar.Wallpaper等重要"颜值绘制/处理"模块 第6章 深入理解控件(ViewRoot)系统(节选) 本章主要内容: ·  介绍创建

[深入理解Android卷一全文-第六章]深入理解Binder

由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. 第6章 深入理解Binder 本章主要内容 ·  以MediaServer为切入点,对Binder的工作机制进行分析. ·  剖析ServiceManager的原理. ·  以MediaPlayerService为切入点对Client和Service的交互进行分析. ·  学以致用,探讨如何写自己的Servi

C#图解教程 第六章 深入理解类

深入理解类 类成员成员修饰符的顺序实例类成员静态字段从类的外部访问静态成员 静态字段示例静态成员的生存期 静态函数成员其他静态类成员类型成员常量常量与静态量属性 属性声明和访问器属性示例使用属性属性和关联字段执行其他计算只读和只写属性属性与公共字段计算只读属性示例自动实现属性静态属性 实例构造函数 带参数的构造函数默认构造函数 静态构造函数对象初始化语句析构函数readonly修饰符this关键字索引器 什么是索引器索引器和属性声明索引器索引器的set访问器索引器的get访问器关于索引器的补充为

第四章 语句 Lua程序设计笔记

--第四章 语句--4.1 赋值Lua支持多重赋值,先对等号右边所有元素求值,然后进行赋值.这可以用来交换变量x, y = y, x 若值的个数少于变量的个数,则多余的变量会被赋值为nil.若值的个数多余变量的个数,则多余的值会被丢弃. --4.2局部变量与块block局部变量的作用域仅限于声明它们的那个块.一个快可以是一个执行体.一个函数或者一个chunk 尽可能使用局部变量:1避免搞乱全局环境2访问局部变量更快3局部变量随其作用域结束而消失,GC可以释放其值. local foo = foo

第三章 表达式 Lua程序设计笔记

--第三章 表达式--3.1 算数操作符--3.2 关系操作符其计算结果是true或false.如果两个值的类型不同,则Lua认为他们不相等.nil只与自身相等.对于table.userdata和函数,Lua作引用比较,只有当它们引用同一个对象时,才认为它们相等. --3.3逻辑操作符--3.4字符串连接Lua中字符串是不可变的值,连接操作符只会创建一个新字符串,而不会对员操作数进行修改.--3.5优先级Lua二元操作符中只有^ 和..是右结合,其他都是左结合 --3.6table构造式{} 混

第十三章 元表与元方法 Lua程序设计笔记

--第十三章 元表与元方法Lua中每个值都有一个表.table和userdata可以有各自独立的元表,其他类型的值共享一个元表.Lua中只能设置table的元表.若要设置其他类型的值的元表,则必须通过C代码来完成. --13.1算数类型的元方法 Set = {} local mt = {} --创建元表 function Set.new(l)--根据参数列表中的值创建一个新的集合 local set = {} setmetatable(set, mt) --设置元表 for _,v in ipa

第六章 实验报告 (函数与宏定义)

C程序设计实验报告 实验项目: 6.4.1.1编写由三角形三边求面积的函数 6.4.1.2编写求N的阶层 6.4.1.3求两个整数的最大公约数 6.4.1.4打印输出的指定图形 6.4.2.1模块化程序设计 姓名:杨婷 实验地点:教学楼514教室 实验时间:2019年4月30日 一.实验目的与要求 <1>6.4.1.1编写由三角形三边求面积的函数 调用area()函数求三角形的面积 在求面积函数中运用海伦公式 <2>6.4.1.2编写求N的阶层 定义符号常量 使用长整型变量存放累乘