C++ 调用 Lua 函数

零、前言

Lua 作为一门脚本语言,可以作为 “配置文件”、“动态逻辑脚本” 等角色作用于宿主程序。

因为他是一门语言,所以他有以下的好处:

1. Lua 会处理语法细节,后续维护简单,并且可以有注释。
2. 可以编写逻辑,达到复杂的配置。

如果我们的程序需要进行一些 “下发配置” 时,一般会考虑选择 “json”、“文件” 等形式。但是如果 “配置” 内容较为复杂,则可以考虑 Lua 了,具体可以查看以下分享。

一、运行 Lua 文件

在之前 “C++ 与 Lua 交互异常处理” 的文章中,已分享如何在 C/C++ 中使用 Lua 文件,这里复习一下。

可以通过 lua_calllua_pcall 两个函数调用 Lua 代码。

int lua_call(lua_State *L, int nargs, int nresults);int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);

两者均用于在 C/C++ 代码中调用 Lua 函数,不同点在于:

  • lua_call 会将代码中的异常直接抛出,导致程序中断。
  • lua_pcall 提供一个保护模式运行 Lua 代码,即使发生异常,也会被捕获,并可以通过第四个参数的错误处理函数处理错误,程序不会因此而中断。

参数:

  • 参数 L: Lua State 的指针。
  • 参数 nargs: 传递给被调用函数的参数个数。
  • 参数 nresults: 期望的返回值个数。
  • 参数 errfunc: 错误处理函数的索引,用于处理发生的错误。如果为 0,则错误信息会被压入栈顶。

返回值:

  • 函数调用成功,返回 0,并将返回值压入栈中。
  • 如果函数调用发生错误,返回一个非零值,并将错误信息压入栈中。

错误处理的细节可以翻阅之前的 “C++ 与 Lua 交互异常处理” 文章。

举个例子

我们通过 lua_pcall 加载一个 Lua 文件,然后在调用 Lua 中的一个函数计算数值,最后获取返回结果。

Lua 文件的内容

function luaFunction(x, y)return (x ^ 2 * math.sin(y)) / (1 - x)
end

接下来看宿主如何运行和调用,可以结合着注释理解。思路是:

  1. 使用 luaL_loadfile 加载 Lua 文件
  2. 使用 lua_pcall 运行 Lua 文件,此时 Lua 中的 luaFunction 是一个全局变量
  3. luaFunction 压入栈,同时将需要传递的参数压入栈,然后通过 lua_pcall 调用函数
  4. 最后使用出栈函数获取结果,因为这里为数值,所以使用 lua_tonumberx 出栈函数
// C++ 入口
void cppCallLuaFunction() {std::string fname = PROJECT_PATH + "/5、C++调用Lua代码/调用Lua函数/调用Lua函数.lua";lua_State *L = luaL_newstate();luaL_openlibs(L);// 加载 Lua 文件、运行 Lua 文件if (luaL_loadfile(L, fname.c_str()) || lua_pcall(L, 0, 0, 0)) {printf("can't run config. file: %s\n", lua_tostring(L, -1));lua_close(L);return;}double calResult = 0;bool isSuccess = false;// 调用 Lua 文件中的函数isSuccess = callLuaFunction(L, 2, 34, &calResult);if (isSuccess) {printf("调用 Lua 成功 luaFunction: %f\n", calResult);} else {printf("调用 Lua 失败\n");}lua_close(L);
}// 调用 Lua 函数
bool callLuaFunction(lua_State *L, double x, double y, double *result) {// 获取全局中的 luaFunction 变量,将其压入栈中int getResult = lua_getglobal(L, "luaFunction");if (getResult == LUA_TNIL) {printf("lua_getglobal get failure\n");return false;}// 将 x 和 y 入栈,会作为 luaFunction 函数的两个参数lua_pushnumber(L, x);lua_pushnumber(L, y);// 运行 luaFunction 函数if (lua_pcall(L, 2, 1, 0) != LUA_OK) {printf("error running function 'f': %s", lua_tostring(L, -1));return false;}int isNum;// 获取 luaFunction 的返回值*result = lua_tonumberx(L, -1, &isNum);if (!isNum) {printf("function 'luaFunction' should return a number.");return false;}// 需要将返回值弹出lua_pop(L, 1);return true;
}// --> 调用 Lua 成功 luaFunction: -2.116331

二、lua_getglobal

在上面一小节中使用到了 lua_getglobal ,这里详细阐述下这一函数的作用

int (lua_getglobal) (lua_State *L, const char *name);

作用:

用于获取全局变量的值,并将其压入 Lua 栈中。

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 name: 要获取的全局变量的名称,以字符串形式表示。

返回值:

如果成功获取到全局变量,则返回该变量在栈中的索引(索引是从 1 开始的整数)。

如果未找到指定的全局变量,则返回 LUA_TNIL。

三、配置文件

在前言一节中,分享用 Lua 文件作为 “配置文件”,这一小节则围绕这一用法展开分享他的好处和讲解如何在 C++ 中调用 Lua 文件。

1、根据环境执行不同逻辑

有时我们需要根据不同的环境,配置一些不同的参数。可以在 Lua 文件中通过 os.getenv 获取系统配置的环境变量,进行返回不同的配置信息。

首先,需要在运行的机器中配置环境变量,我的电脑是 Mac ,配置在 ~/.zshrc 中。

~/.zshrc 配置内容如下所示

export DISPLAY_ENV="Mac"

然后在 Lua 中进行获取使用,Lua 的内容如下

-- DISPLAY_ENV 在环境变量中配置,open ~/.zshrc 可以查看
local displayEnv = os.getenv("DISPLAY_ENV");
print("displayEnv", displayEnv)if displayEnv == "Mac" thenwidth = 3072height = 1920
elsewidth = 1920height = 1080
end

最后通过 C++ 加载和运行该 Lua 文件

void loadConfigUseEnv() {std::string filename = PROJECT_PATH + "/5、C++调用Lua代码/Lua作为配置文件/根据环境变量获取值/config.lua";lua_State *L = luaL_newstate();luaL_openlibs(L);if (luaL_loadfile(L, filename.c_str()) || lua_pcall(L, 0, 0, 0)) {printf("can't run config. file: %s\n", lua_tostring(L, -1));return;}int width;if (!getGlobInt(L, "width", &width)) {printf("Get width failure.");return;}int height;if (!getGlobInt(L, "height", &height)) {printf("Get height failure.");return;}printf("size: %d x %d\n", width, height);lua_close(L);
}bool getGlobInt(lua_State *L, const char *var, int *result) {int isNum;// 将 var 对应的值压入栈中lua_getglobal(L, var);*result = (int) lua_tointegerx(L, -1, &isNum);if (!isNum) {printf("'%s' should be a number\n", var);return false;}// 将 var 对应值压入栈中的值弹出lua_pop(L, 1);return true;
}

会输出以下内容

displayEnv	Mac
size: 3072 x 1920

可以看到,Lua 脚本会获取我们电脑的环境变量,根据值执行不同的逻辑,这一点在 json、文本配置文件是无法做到的。

2、预设配置

宿主可以初始化一些配置选项给到 Lua ,Lua 根据所需进行使用,当然也可以自行生成配置项,这一过程只是业务逻辑上的设计。

下面举个例子,假设需要给一个 App 配置一个主题色,颜色用 rgb 进行表示,在 Lua 中可以用 table 进行装载颜色,让数据联系更加紧凑,可以内置一些颜色给到 Lua 进行使用。

话不多说,下面开始演示这一过程是如何使用。

第一步,我们需要先将内置的颜色值设置到 Lua 中。 需要先创建一个表 table ,然后将 key - value 放置到 table 中。

在下面的 setColor 方法中,会先创建一个 table ,然后通过封装的 setColorField 方法将 red、green、blue 放置到 table 中。

setColorField 中会将 key、value 按顺序压栈,然后通过 lua_settable 设置到对应的索引表中。

lua_newtable、lua_createtable、lua_settable、lua_setfield 这些 api 会在接下来的小节进行详细讲解

void setColor(lua_State *L, struct ColorTable *ct) {// 创建一个空表,并压入栈顶// lua_newtable 这是一个宏,真是定义是 lua_createtable(L, 0, 0)// lua_newtable 和 lua_createtable 会压入一个 table 到栈中lua_newtable(L);
//    lua_createtable(L, 0, 3);setColorField(L, "red", ct->red);setColorField(L, "green", ct->green);setColorField(L, "blue", ct->blue);// 'name' = table// 弹出表,并且将其设置为指定名称的全局变量的值lua_setglobal(L, ct->name);
}void setColorField(lua_State *L, const char *index, int value) {// 第一种// 键lua_pushstring(L, index);// 值lua_pushnumber(L, (double) value / MAX_COLOR);// 将键和值弹出,然后设置到 table (索引为 -3) 中,table[stack[-2]] = stack[-1]lua_settable(L, -3);// 第二种
//    lua_pushnumber(L, (double) value / MAX_COLOR);
//    lua_setfield(L, -2, index);
}

经过这一步的设置,在 Lua 中就可以查看到对应的值了。

第二步,加载和运行 Lua 文件,在 Lua 文件中使用第一步设置的值,将其返回给宿主

Lua 文件内容如下

print(PINK, PINK.red, PINK.green, PINK.blue)
-- c++ 获取到的为 table
background = PINK
-- c++ 获取到的为 string
--background = "PINK"

加载和运行的代码如下

#define MAX_COLOR 255struct ColorTable {char *name;unsigned char red, green, blue;
} colorTable[] = {{"WHITE", MAX_COLOR, MAX_COLOR, MAX_COLOR},{"RED",   MAX_COLOR, 0,         0},{"GREEN", 0,         MAX_COLOR, 0},{"BLUE",  0,         0,         MAX_COLOR},{"PINK",  255,       192,       203},{nullptr, 0,         0,         0}
};void load(lua_State *L, const char *fname) {int i = 0;// 设置颜色值while (colorTable[i].name != nullptr) {setColor(L, &colorTable[i++]);}if (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0)) {printf("can't run config. file: %s\n", lua_tostring(L, -1));return;}// ... 获取值的操作,下面分享
}void loadConfigUseTable() {std::string filename = PROJECT_PATH + "/5、C++调用Lua代码/Lua作为配置文件/配置中使用表/config.lua";lua_State *L = luaL_newstate();luaL_openlibs(L);load(L, filename.c_str());lua_close(L);
}

第三步,获取 Lua 返回的值

将 Lua 中对应的 “background” 变量压入栈,然后将 key 压入栈,通过 lua_gettable 获取对应的值。

bool getColorField(lua_State *L, const char *key, int *result) {int isNum;// 第一种做法// 将 key 压入栈lua_pushstring(L, key);// 将栈顶(key)弹出,然后将读取的值压入lua_gettable(L, -2);// 第二种做法(lua_getfield 和 lua_gettable 都会返回类型)
//    if (lua_getfield(L, -1, key) == LUA_TNUMBER) {
//        printf("invalid component in background color");
//        return false;
//    }*result = (int) (lua_tonumberx(L, -1, &isNum) * MAX_COLOR);if (!isNum) {printf("invalid component '%s' in color", key);return false;}lua_pop(L, 1);return true;
}void load(lua_State *L, const char *fname) {// ... 加载和运行 Lua 文件// 将 background 压入栈lua_getglobal(L, "background");if (lua_istable(L, -1)) {int red;if (!getColorField(L, "red", &red)) {printf("Get red failure.\n");return;}int green;if (!getColorField(L, "green", &green)) {printf("Get green failure.\n");return;}int blue;if (!getColorField(L, "blue", &blue)) {printf("Get blue failure.\n");return;}printf("table color: (%d, %d, %d)\n", red, green, blue);} else if (lua_isstring(L, -1)) {const char *name = lua_tostring(L, -1);int i;for (i = 0; colorTable[i].name != nullptr; i++) {if (strcmp(name, colorTable[i].name) == 0) {break;}}if (colorTable[i].name == nullptr) {printf("invalid color name (%s)", name);return;}int red = colorTable[i].red;int green = colorTable[i].green;int blue = colorTable[i].blue;printf("string color: (%d, %d, %d)\n", red, green, blue);} else {printf("'background' is not a table.");}
}

最后会输出

table: 0x600001afc880	1.0	0.75294117647059	0.79607843137255
table color: (255, 192, 203)

四、lua_newtable

void lua_newtable(lua_State *L);

作用:

用于创建一个新的空表,并将其压入 Lua 栈中。

参数:

  • 参数 L: Lua 状态机(Lua state)指针。

返回值:

没有返回值,但会压入一个 table 在栈顶。

五、lua_createtable

lua_newtable 其实是一个宏定义,真正实现是 lua_createtable

#define lua_newtable(L)		lua_createtable(L, 0, 0)
void  (lua_createtable) (lua_State *L, int narr, int nrec);

作用:

用于创建一个新的表,并将其压入 Lua 栈中。

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 narr: 表的数组部分初始容量。数组部分是用于存储连续整数键(索引)的区域。当按顺序插入整数键时,它们会被存储在数组部分中,以实现高效的数组访问。narr 的值可以是正整数,用于指定表初始化时预分配的数组部分的大小。如果 narr 为 0,则表示不分配数组部分。
  • 参数 nrec: 表的哈希部分初始容量。哈希部分是用于存储非整数键(如字符串键)的区域。当我们插入非整数键时,它们会被存储在哈希部分中,并使用哈希表来实现高效的键值对查找。nrec 的值可以是正整数,用于指定表初始化时预分配的哈希部分的大小。如果 nrec 为 0,则表示不分配哈希部分。

一般情况下,如果事先知道表的大致大小,设置适当的 narr 和 nrec 值可以提高表操作的效率。但如果不确定表的大小,或者表的大小会动态变化,设置为 0 会让 Lua 在需要时自动调整表的大小。Lua 在内部会根据需要动态调整表的大小,以适应实际的键值对数量。

返回值:

没有返回值,但会压入一个 table 在栈顶。

六、lua_gettable

int (lua_gettable) (lua_State *L, int idx);

作用:

用于从 Lua 栈中获取表中指定键的值,并将该值压入栈顶

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 index: 表示要获取表的索引位置。如果索引为正数,则表示从栈底向上数的位置获取表;如果索引为负数,则表示从栈顶向下数的位置获取表。

返回值:

返回数据类型,并且会将获取到的值压入栈顶,如果没有找到对应的值,则会将 nil 压入(因为在 table 中查询一个不存在的键时,则会返回 nil )。

返回的数据类型有以下类型,可以根据类型判断是否符合期望。

#define LUA_TNIL		0
#define LUA_TBOOLEAN		1
#define LUA_TLIGHTUSERDATA	2
#define LUA_TNUMBER		3
#define LUA_TSTRING		4
#define LUA_TTABLE		5
#define LUA_TFUNCTION		6
#define LUA_TUSERDATA		7
#define LUA_TTHREAD		8

一图胜千言:

七、lua_getfield

和 lua_gettable 的作用一样,只是更加便捷,不用额外的将 key 压入栈顶。

int (lua_getfield) (lua_State *L, int idx, const char *k);

作用:

用于获取指定表(索引为 idx )中字段名为 k 的值。

参数:

  • 参数 L: Lua 状态机的指针。
  • 参数 index: 表在堆栈中的索引。如果索引为正数,则表示从栈底向上数的位置获取表;如果索引为负数,则表示从栈顶向下数的位置获取表。
  • 参数 k: 字段的名称,以 C 字符串的形式传递。

返回值:

返回数据类型,并且会将获取到的值压入栈顶,如果没有找到对应的值,则会将 nil 压入(因为在 table 中查询一个不存在的键时,则会返回 nil )。

返回的数据类型有以下类型,可以根据类型判断是否符合期望。

#define LUA_TNIL		0
#define LUA_TBOOLEAN		1
#define LUA_TLIGHTUSERDATA	2
#define LUA_TNUMBER		3
#define LUA_TSTRING		4
#define LUA_TTABLE		5
#define LUA_TFUNCTION		6
#define LUA_TUSERDATA		7
#define LUA_TTHREAD		8

八、lua_settable

void lua_settable(lua_State *L, int index);

作用:

用于将键(索引为 -2 )、值(索引为 -1 )对存储到表(索引为 index )中。

可以理解为 table[stack[-2]] = stack[-1] ,table 为 stack[index]

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 index: 表示要获取表的索引位置。如果索引为正数,则表示从栈底向上数的位置获取表;如果索引为负数,则表示从栈顶向下数的位置获取表。

返回值:

没有返回值,会将键和值出栈。

九、lua_setfield

和 lua_settable 的作用一样,只是更加便捷,不用将 key 值压入到栈中,但还是需要将 value 压至栈顶。

void lua_setfield(lua_State *L, int index, const char *key);

作用:

用于将值(索引为 -1 )存储到指定表(索引为 index )中的指定键名(key)。

可以理解为 table[index] = stack[-1] ,table 为 stack[index]

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 index: 表在栈中的索引位置。如果索引为正数,则表示从栈底向上数的位置获取表;如果索引为负数,则表示从栈顶向下数的位置获取表。
  • 参数 key: 作为键的字符串。是一个 C 字符串,表示要在表中使用的键名。

返回值:

没有返回值,会将栈顶的 value 出栈。

十、lua_setglobal

void lua_setglobal(lua_State *L, const char *name);

作用:

用于将值(索引为 -1 )以 name 作为属性名存储到全局变量中。

可以理解为 'name' = value

参数:

  • 参数 L: Lua 状态机(Lua state)指针。
  • 参数 name: 是一个 C 字符串,表示要存储值的全局变量名。

返回值:

没有返回值,会将栈顶值弹出。

十一、写在最后

Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)

如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀

公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。

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

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

相关文章

IDEA 快捷键汇总

目录 1、altinsert 2、ctrl/ 3、altenter 4、alt回车 5、ctrlD 6、ctrlaltL 7、ctrl点击 8、alt左键向下拉 9、ctrlaltv 10、ctrlaltwint 1、altinsert 快速创建代码,可以快速创建类中get set tostring等方法 2、ctrl/ 单行注释 3、altenter…

水库大坝安全监测系统守护水利工程安全的坚实后盾

WX-WY1 随着社会经济的发展和科技的进步,水利工程的安全问题越来越受到人们的关注。水库大坝作为水利工程的重要组成部分,其安全状况直接关系到周边地区人民的生命财产安全和生态环境。因此,建立一个高效、可靠的水库大坝安全监测系统至关重要…

特效!视频里的特效在哪制作——Adobe After Effects

今天,我们来谈谈一款在Adobe系列中推出的一款图形视频处理软件,适用于从事设计和视频特技的机构,包括电视台、动画制作公司、个人后期制作工作室以及多媒体工作室的属于层类型后期软件——Adobe After Effects。 Adobe After Effects&#xf…

qt槽函数的四种写法

槽函数的四种写法 一,Qt4写法 不推荐这种写法,如果SLGNAL写错了,或者信号名字,槽函数名字写错了.编译器检查不出来,导致程序无响应,引起不必要的误解 connect(ui.btnOpen,SLGNAL(clicked),this,SLOT(open()));二,Qt5写法 推荐使用这种写法,信号名字、槽函数名字…

gitlab利用CI多工程持续构建

搭建CI的过程中有多个工程的时候,一个完美的构建过程往往是子工程上的更新(push 或者是merge)触发父工程的构建,这就需要如下建立一个downstream pipeline 子仓库1 .gitlab-ci.yml stages:- buildbuild_job:stage: buildtrigger:project: test_user/tes…

-bash: jps: command not found

背景 服务器的jdk通过yum 安装的,要用jps查询pid,提示找不到命令 yum install -y java-1.8.0-openjdk.x86_64 一、jps命令无法找到 [devhgh-tob-hsbc-dev-003 ~]$ jps -bash: jps: command not found 二、检查基础Java环境 [devhgh-tob-hsbc-dev-003 ~]…

计算机是如何工作的(简单介绍)

目录 一、冯诺依曼体系 二、CPU基本流程工作 逻辑⻔ 电⼦开关——机械继电器(Mechanical Relay) ⻔电路(Gate Circuit) 算术逻辑单元 ALU(Arithmetic & Logic Unit) 算术单元(ArithmeticUnit) 逻辑单元(Logic Unit) ALU 符号 寄存器(Regis…

KVM Cloud云平台

项目介绍 KVM Cloud 是一款基于Java实现的轻量级私有云平台,旨在帮助中小企业快速实现计算、存储、网络等资源的管理,让企业拥有自己的云平台,包括但不限于如下功能: 1、基于KVM的VM基础功能(创建、启动、停止、重装、webVNC等功能) 2、使用…

卷积神经网络(CNN)衣服图像分类的实现

文章目录 前期工作1. 设置GPU(如果使用的是CPU可以忽略这步)我的环境: 2. 导入数据3.归一化4.调整图片格式5. 可视化 二、构建CNN网络模型三、编译模型四、训练模型五、预测六、模型评估 前期工作 1. 设置GPU(如果使用的是CPU可以…

JVM——运行时数据区(程序计数器+栈)

目录 1.程序计数器2.栈Java虚拟机栈 - 栈帧的组成1.Java虚拟机栈-局部变量表3.Java虚拟机栈-操作数栈3.Java虚拟机栈-帧数据 3.Java虚拟机栈-栈内存溢出4.本地方法栈 ⚫ Java虚拟机在运行Java程序过程中管理的内存区域,称之为运行时数据区。 ⚫ 《Java虚拟机规范》中…

Unity减少发布打包文件的体积(二)——设置WebGL发布时每张图片的压缩方式

一个项目在发布成WebGL后,其体积至关重要,体积太大,用户加载会经历一个漫长的等待…轻则骂娘,重则用脚把电脑踢烂(扣质保金)… 那么如何减少发布后的体积呢,本文从图片的压缩开始入手。 前传回顾: Unity减…

Linux mmap 的作用是什么?

文章目录 1.简介2.相关函数3.mmap和常规文件操作的区别4.作用参考文献 1.简介 mmap&#xff08;memory map&#xff09;即内存映射&#xff0c;用于将一个文件或设备映射到进程的地址空间。 2.相关函数 创建映射函数&#xff1a; #include <sys/mman.h>void *mmap(v…

Upwork 新手使用指南——如何快速在Upwork上接单

Upwork 这个自由职业平台不知道大家听说过没&#xff0c;在 Upwork&#xff0c;如果你是自由职业者&#xff0c;你可以接单&#xff1b;如果你是客户&#xff0c;你可以找人干活。但对于新手来说&#xff0c;怎么使用 Upwork 并且用好 Upwork 是一大难题。因此今天给大家分享 U…

你好,我叫Python,欢迎你认识派森。(来自关于Python语言的全方位自我介绍。

文章目录 自我简介一、Python的发展历程二、Python的特色1.语言特色2.语法特色 三、Python2与Python3的比较1.print 函数2.Unicode3.除法运算4.异常5.八进制字面量表示6.不等运算符7.python 3.0严格使用tab键进行缩进 四、Python适用开发场景及成果1.应用领域2.Python开发出的应…

python科研绘图:P-P图与Q-Q图

目录 什么是P-P图与Q-Q图 分位数 百分位数 Q-Q图步骤与原理 Shapiro-Wilk检验 绘制Q-Q图 绘制P-P图 什么是P-P图与Q-Q图 P-P图和Q-Q图都是用于检验样本的概率分布是否服从某种理论分布。 P-P图的原理是检验实际累积概率分布与理论累积概率分布是否吻合。若吻合&#xf…

srs webrtc推拉流环境搭建(公网)

本地环境搭建 官方代码https://github.com/ossrs/srs 拉取代码&#xff1a; git clone https://github.com/ossrs/srs.gitcd ./configure make ./objs/srs -c conf/https.rtc.confsrs在公网上&#xff0c;由于srs是lite-ice端&#xff0c;导致他不会主动到srs获取自己的公网i…

MySQL的执行器是怎么工作的

作为优化器后的真正执行语句的层&#xff0c;执行器有三种方式和存储引擎&#xff08;一般是innoDB&#xff09;交互 主键索引查询 查询的条件用到了主键&#xff0c;这个是全表唯一的&#xff0c;优化器会选择const类型来查询&#xff0c;然后while循环去根据主键索引的B树结…

nn.KLDivLoss,nn.CrossEntropyLoss,nn.MSELoss,Focal_Loss

KL loss&#xff1a;https://blog.csdn.net/qq_50001789/article/details/128974654 https://pytorch.org/docs/stable/nn.html 1. nn.L1Loss 1.1 公式 L1Loss: 计算预测 x和 目标y之间的平均绝对值误差MAE, 即L1损失&#xff1a; l o s s 1 n ∑ i 1 , . . . n ∣ x i…

Java 设计模式——桥接模式

目录 1.概述2.结构3.实现3.1.实现化类3.2.具体实现化类3.3.抽象化类3.4.扩展抽象化类3.5.测试 4.优缺点5.使用场景 1.概述 &#xff08;1&#xff09;现在有一个需求&#xff0c;需要创建不同的图形&#xff0c;并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来…

数据结构与算法之美学习笔记:22 | 哈希算法(下):哈希算法在分布式系统中有哪些应用?

目录 前言应用五&#xff1a;负载均衡应用六&#xff1a;数据分片应用七&#xff1a;分布式存储解答开篇 & 内容小结 前言 本节课程思维导图 今天&#xff0c;我们再来看剩余三种应用&#xff1a;负载均衡、数据分片、分布式存储。你可能已经发现&#xff0c;这三个应用都…