【Lua学习笔记】Lua进阶——函数和闭包

news2024/11/24 10:52:07

在这里插入图片描述

文章目录

  • 函数
    • 函数嵌套
    • 闭包Closures
    • 可变函数
    • 函数重载


函数

函数嵌套

function A()
    print("这里是函数A")
	return function ()
        print("返回函数不要起名")
    end
end
B = A()
B()

输出:
这里是函数A
返回函数不要起名

使用函数嵌套的用法,我们可以将另一个函数作为返回值,但是返回函数作为一个值是要被赋值给其他变量的,所以return时不能起名(赋值)为其他变量名。


闭包Closures

推荐阅读深入Lua:函数和闭包

在函数嵌套中,我们需要接触一个叫做闭包的概念

这就是一个闭包,它由一个函数和该函数会访问到的非局部变量(或者说upvalue)组成

function f1(n)
   --函数参数n也是局部变量
   local function f2()
      print(n)   --引用外部函数的局部变量,即upvalue
   end
   return f2
end

a =f1(1) --注意,闭包不传入参数则为nil
a()

当一个函数内嵌套另一个函数的时候,内函数可以访问外部函数的局部变量,这种特征被称为词法域,什么意思呢?

例如上述f1的入参n,它是一个形参,也是f1内的局部变量。现在f1内部定义了另一个函数f2,显然f2需要访问f1内的局部变量 n。但是对于n而言,它的词法域或者说作用域只是在f1内。如果只是简单的函数嵌套的话,用其他语言可以是这样实现的:

void f1(int x){
	f2(x)
}
void f2(int x){
	return x
}

但是问题是上述定义中f1内的x和f2内的x并不是同一个x,而分别是它们作用域内定义的局部变量。

而闭包更相当于一个指针,使得f2直接引用了f1的局部变量

#include <iostream>
using namespace std;
void f2(int *x)
{
	printf("%d", *x);
}
void f1(int x)
{
	f2(&x);
}
int main()
{
	int i = 1;
	f1(i);
	return 0;
}

这就是闭包的概念:内部函数innerFunction能够访问并持有其外部函数outerFunction作用域中的变量,这些被内部函数引用的外部函数的局部变量被称为upvalues。实际上,一般的函数在lua中是一种特殊的闭包。整个函数产生的闭包类似于下列struct :

// Lua闭包
typedef struct LClosure {
  ClosureHeader;
  struct Proto *p;    // 函数原型
  UpVal *upvals[1];  /* list of upvalues */   // upvalue列表
} LClosure;
function Create(n)
   local function f1()
      print(n)
   end
   local function f2()
      n = n + 10
   end
   return f1,f2
end
a,b = Create(10)
a() -- 10
b()
a() -- 20
b()
a() -- 30

在上述闭包中,两个闭包f1,f2使用的n是同一个局部变量,因此f2使n增加后,f1输出值也变了。它们共享一个upvalues。

现在假设要创建一个对象,对外只提供有限的访问接口,而对象内部的数据不能直接被修改,那么我们可以这样写:

local function new_object()
    local obj = {       -- 这就是要创建的对象
        _data1 = 1,     -- 假设这是内部数据
        _data2 = 2,     -- 这是外部可修改的数据
    }
    return {            -- 这是返回的接口table
        get_data2 = function() return obj._data2 end,
        set_data2 = function(value) obj._data2 = value end,
    }
end

local obj_inteface = new_object()
obj_inteface.set_data2(100)
print(obj_inteface.get_data2())     --> 100

可变函数

function f1( x,...)
    arg={...}
    for i=1,#arg do
        print(arg[i])
    end
end

我们用…表示参数是可变参数,它能接收任意长的参数,但是在我们使用的时候,最好使用一个table来接收这个可变参数。此外其他固定的入参一定要放在可变参数的前面,这样函数才能先接受入参,其他的丢给可变参数。


函数重载

function A()
	print(123)
end
A()

function A(a)
	print(a)
end
A(1)

输出:
123
1

在Lua中,函数的重载十分简单,只需在函数下方重写这个函数即可。在Unity中Lua能实现热更新,例如修正一些Bug,就是通过重载函数实现的,举个例子:
摘自Lua语言:函数级别的重载

-- hotfix.lua
--- 执行热更新
-- oldmod是旧模块
-- newmod是新模块,这个模块里只会提供要替换的函数,相当于旧模块的一个子集。
function hotfix.run(oldmod, newmod)
    -- 收集旧模块的所有upvalue
    local uvmap = collect_all_upvalue(oldmod)
    for k, v in pairs(newmod) do
        if type(v) == 'function' then
            -- 这里就是先把新函数的upvalue修正,然后直接替换给旧模块
            oldmod[k] = hotfix_func(v, uvmap)
        end
    end
end
return hotfix

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/795121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot 之以enable开头的注解

Spring​ 有很多 Enable 开头的注解&#xff0c;平时在使用的时候也没有注意过为什么会有这些注解 Enable 注解 首先我们先看一下有哪些常用的 Enable 开头的注解&#xff0c;以及都是干什么用的。 EnableRetry​&#xff1a;开启Spring 的重试功能&#xff1b; EnableSch…

Guitar Pro8吉他谱制作软件好不好用?

吉他谱是学习和演奏吉他的重要工具之一&#xff0c;对于吉他爱好者而言&#xff0c;掌握一款优秀的吉他谱制作软件是必不可少的。随着科技的进步&#xff0c;现在有许多吉他谱制作软件可供选择。下面我们就来看吉他谱制作软件哪个好&#xff0c;以及怎么制作吉他谱子吧&#xf…

Vue前端渲染blob二进制对象图片的方法

近期做开发&#xff0c;联调接口。接口返回的是一张图片&#xff0c;是对二进制图片处理并渲染&#xff0c;特此记录一下。 本文章是转载文章&#xff0c;原文章&#xff1a;Vue前端处理blob二进制对象图片的方法 接口response是下图 显然&#xff0c;获取到的是一堆乱码&…

HEVC网络适配层介绍

h265 的分层结构 分层结构的目的 ○ 网络类型多种多样&#xff0c;不同的网络环境具有不同的特性&#xff0c;压缩视频在其中进行传输必然会受到影响&#xff1b;比如不同网络的 MTU 有所不同&#xff1b; ○ 不同的应用场景对视频有不同的需求&#xff0c;视频业务会喜用不…

Llama 2 来袭 - 在 Hugging Face 上玩转它

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 引言 今天&#xff0c;Meta 发布了 Llama 2&#xff0c;其包含了一系列最先进的开放大语言模型&#xff0c;我们很高兴能够将其全面集成入 Hugging Face&#xff0c;并全力支持其发布。Llama 2 的社…

Sentinel Dashboard集成Nacos

1.前言 当项目上Sentinel Dashboard做流量监控的时候&#xff0c;我们可以通过Sentinel控制台修改限流配置&#xff0c;但当我们使用Nacos作为配置中心动态配置流控规则的时候&#xff0c;问题就来了。 首先我们要明白&#xff0c;Sentinel Dashboard的配置是从机器的内存中加…

go学习 3、基础数据类型

3、基础数据类型 基础数据类型&#xff1a;数字、字符串、布尔型复合类型&#xff1a;数组、结构体引用类型&#xff1a;指针、切片、字典、函数、通道接口类型 3.1 整型 有符号、无符号 int8/int16/int32/int64 uint8/uint16/uint32/units 64 Unicode字符rune类型是和int32…

R语言无法调用stats.dll的问题解决方案[补充]

写在前面 在去年10月份&#xff0c;出过一起关于R语言无法调用stats.dll的问题解决方案,今天&#xff08;你看到后是昨天&#xff09;不知道为什么&#xff0c;安装包&#xff0c;一直安装不了&#xff0c;真的是炸裂了。后面再次把R与Rstuido升级。说实话&#xff0c;我是真不…

整套停车位地磁检测方案出售,主控使用stm32驱动nb-iot模块bc95数据上传远程云服务器。

地磁车辆检测器&#xff0c;是车辆本身含有的铁磁物质会对车辆存在区域的地磁信号产生影响&#xff0c;使车辆存在区域的地球磁力线发生弯曲。当车辆经过传感器附近&#xff0c;传感器能够灵敏感知到信号的变化&#xff0c;经信号分析就可以得到检测目标的相关信息。 朋友创业…

安装github中的存储库作为Python包

第一步&#xff0c;安装git 安装教程&#xff1a;https://zhuanlan.zhihu.com/p/114068278 第二步&#xff0c;在github上复制该库的链接 第三步&#xff0c;使用命令行一键下载并安装包 pip install "githttps://github.com/openai/CLIP.git"如果当pip install…

笔记本充满电后,充电器可以长期不拔,会议安全隐患吗?

笔记本充满电后&#xff0c;一直插着不拔 1.建议人在身边可以暂时不拔&#xff0c;偶尔还是要使用电池当笔记本电池充满之后&#xff0c;电脑会自动使用电源供电&#xff0c;不会使用电池供电 2.笔记本电池都带有电池保护机制&#xff0c;在电池充满电后会自动停止充电 3.现在…

RNN架构解析——认识RNN模型

目录 RNN模型作用分类按照输入和输出的结构进行分类按照RNN的内部构造进行分类 RNN模型 RNN单层网络结构 作用 分类 按照输入和输出的结构进行分类 按照RNN的内部构造进行分类

Ftp和UDP的区别之如何加速文件传输

FTP&#xff08;文件传输协议&#xff09;是一种传输大文件的老方法&#xff0c;它的速度慢&#xff0c;而且容易受到网络环境的影响。在当今这个文件越来越大&#xff0c;项目交付时间越来越紧&#xff0c;工作分布在全球各地的时代&#xff0c;有没有办法让 FTP 加速呢&#…

JS学习第二部分

在前面&#xff0c;第一章节 &#xff0c;学了JS的基本语法和一些常用的用法。在第二章节&#xff0c; 学了DOM&#xff0c;就是节点信息&#xff0c;教我们怎么在JS里面获取HTML的标签。接着&#xff0c;我们学习第三章节&#xff0c;怎么在JS里面对HTML的css样式进行操作。 …

3ds MAX NURBS曲线绘制鼠标

先引用一段大佬的话&#xff0c;解释为什么除了样条线还有这种曲线 NURBS是有理B-splines曲线https://www.zhihu.com/search?q%E6%9C%89%E7%90%86B-splines%E6%9B%B2%E7%BA%BF&search_sourceEntity&hybrid_search_sourceEntity&hybrid_search_extra%7B%22sourceT…

<Postman>Postman接口测试以及使用案例

说明&#xff1a;现在所有的系统都有登录token设置&#xff1b; 所以需要先进行登录&#xff0c;获取两个token&#xff1b; 关于token和refresh token 传统的认证方式一般采用cookie/session来实现&#xff0c;这是我们的出发点。 1.为什么选用token而不选用cookie/session…

OSI模型简介及socket,tcp,http三者之间的区别和原理

1.OSI模型简介&#xff08;七层网络模型&#xff09; OSI 模型(Open System Interconnection model)&#xff1a;一个由国际标准化组织提出的概念模型&#xff0c;试图提供一个使各种不同的计算机和网络在世界范围内实现互联的标准框架。 它将计算机网络体系结构划分为七层,每…

spring 存储对象 + 获取对象

前言 本篇在spring中如何使用五大类注释与方法注释将对象加入IOC容器中&#xff0c;了解如何使用注释来获取容器中的Bean对象&#xff0c;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff01; 文章目录 前言1.通过注释将类加入IoC…

【C++ 重要知识点总结】自定义类型-类和结构体

类 类的基本特性 数据抽象和封装继承多态 1 类的构成——抽象 概念 数据抽象是一种依赖于接口和实现的分离的编程技术。类的接口包括用户所能执行的操作&#xff1b;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需要的的各种私有函数。封装实现了类的接口和实…

645. 错误的集合

645. 错误的集合 class Solution { public static int[] findErrorNums(int[] nums) {Arrays.sort(nums);int dup-1;int miss1;for (int i 1; i < nums.length; i) {if(nums[i]nums[i-1]){dupnums[i];}if(nums[i]-nums[i-1]>1){missnums[i]-1;}}return new int[]{dup,…