# Lua与C++交互(二)———— 交互

C++ 调用lua

基础调用

再来温习一下
myName = “beauty girl”

在这里插入图片描述

  1. C++想要获取myName的值,根据规则,它需要把myName压入栈中,这样lua就能看到;
  2. lua从堆栈中获取myName的值,此时栈顶为空;
  3. lua拿着myName去全局表中查找与之对应的字符串;
  4. 全局表找到,并返回"beauty girl";
  5. lua把"beauty girl"压入栈中;
  6. C++从栈中获取"beauty girl"

用代码来实现

    //创建一个statelua_State *L = luaL_newstate();// 重置栈顶索引 为了确认让栈顶的索引置为0 置0之后,我们入栈的第一个元素的索引就是1lua_settop(L, 0);// 把myName放入栈中,然后lua去全局表中查找,找到对应的字段,再放回栈中lua_getglobal(L, "myName");// 判断栈顶的值的类型是否为String, 返回非0值代表成功int isstr = lua_isstring(L, 1);//获取栈顶的值const char* str = lua_tostring(L, 1);lua_close(L);

C++获取Lua的table

helloTable = {name = “xxx”, sex = “man”}

和上面一样,要获取就先把helloTable放到栈顶,让Lua知道C++要获取这个值

    //创建一个statelua_State *L = luaL_newstate();// 重置栈顶索引 为了确认让栈顶的索引置为0 置0之后,我们入栈的第一个元素的索引就是1lua_settop(L, 0);//获取helloTable的值 这个时候栈底 是 helloTablelua_getglobal(L, "helloTable");//我们想要获取table中name的值,那么就把name压入栈//这个时候栈中是 name,helloTable,其中name是栈顶lua_pushstring(L, "name");//lua api提供了一个获取table的函数 lua_gettable//该函数会从栈顶取得一个值,然后根据这个值去table中寻找对应的值,最后把找到的值放到栈顶 第二个参数是指table变量所在栈中的位置lua_gettable(L, -2); // -1永远是栈顶,那么helloTable就是-2,这里也可以用1//lua_gettable 会把值放到 栈顶 const char* sName = lua_tostring(pL, -1);

C++调用Lua函数

function helloAdd(num1, num2)return (num1 + num2)
end

这里有个新的函数 lua_call

第一个参数表示函数的参数个数,第二个参数表示函数返回值个数

Lua会先去堆栈取出参数,然后再取出函数对象,开始执行函数

    //创建一个statelua_State *L = luaL_newstate();// 重置栈顶索引 为了确认让栈顶的索引置为0 置0之后,我们入栈的第一个元素的索引就是1lua_settop(L, 0);//把helloAdd函数对象放到栈中lua_getglobal(L, "helloAdd");//把函数所需要的参数入栈 lua_pushnumber(L, 10);lua_pushnumber(L, 5);//调用lua_calllua_call(L, 2, 1);int iResult = lua_tonumber(L, -1);

C++调用Lua table的函数

lua中table有两种函数

mytable={}
function mytable.StaticFunc()print("mytable.StaticFunc called.")
end
function mytable:Func()print("mytable:Func self:", self)
end

其中StaticFunc可以理解成table的静态函数,Func为table的成员函数

 // 调用mytable表的静态函数
lua_getglobal(L, "mytable"); // 将名为mytable的全局table变量的值压栈
lua_pushstring(L, "StaticFunc"); // 将函数名为StaticFunc压栈
lua_gettable(L, -2); // 从索引为-2处的表中,读取key(在栈顶处)为StaticFunc的函数名  读取成功后,将key出栈,并将读取到的函数名入栈
lua_call(L, 0, 0); // 执行完后将StaticFunc弹出栈  注: 第一个0表示参数个数为0,第二个0表示无返回值// 调用mytable表的成员函数  采用新方法获取函数名
lua_getfield(L, -1, "Func");// 从索引为-1处的表中,读取key为Func的函数名  成功后将读取到的函数名入栈
lua_pushvalue(L, -2); // 将索引为-2处的表复制一份并压入栈顶
lua_call(L, 1, 0); // 执行完后将Func弹出栈  注: 1表示参数个数,即self指针,为当前table,第二个0表示无返回值

唯一不同的是lua_call的时候,需要注意第二个的值,成员函数默认需要传递self。

这里获取的时候,用到了函数lua_getfield

函数原型如下

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

Pushes onto the stack the value t[k], where t is the value at the given valid index. As in Lua, this function may trigger a metamethod for the “index” event

大概意思,将t[k]压入堆栈,t由参数index指定在栈中的位置

Lua 调用C++

Lua调用C++ 函数

大概的步骤如下:

  1. 将C++的函数包装成Lua环境认可的Lua_CFunction格式
  2. 将包装好的函数注册到Lua环境中
  3. 像使用普通Lua函数那样使用注册函数

简单的C++函数

int add(int a,int b)
{return a+b;
}

包装C++函数

int add(lua_state *L)
{int a = lua_tonumber(-1);int b = lua_tonumber(-2);int sum = a+b;// 将返回值压入栈中lua_pushnumber(L,sum);// 返回返回值个数return 1;
}
  1. Lua脚本里会调用add(lua_state *L)
  2. 调用add(lua_state *L)函数的时候,会反过来进行之前的C++调用lua
  3. Lua调用add(lua_state *L)函数之后,有一个返回值,需要压入栈中
  4. 最后return表示有多少个返回值,Lua支持多个返回值

最关键的一步,需要注册C++的函数,Lua才能调用

lua_register(L, "add", add);

Lua调用C++类

这里有两种方式,一个是用luaL_newlib方式

luaL_newlib方式

大概步骤如下:

  1. 新建创建对象函数,调用lua_newuserdata,创建一个对象指针,指向new出来的新的对象。
  2. 新建成员方法,调用lua_touserdata,得到从lua中传入的对象指针,调用成员方法。
  3. 调用luaL_newlib,将需要封装的C++函数放入到一个lua表中压入栈里。
  4. 将自定义模块,注册到Lua环境中。
  5. 在lua中,会首先调用创建对象函数,获得Student对象指针。通过Student对象指针,调用成员方法

Student.h

#pragma once#include <iostream>
#include <string>
using namespace std;class Student
{
public://构造/析构函数Student();~Student();//get/set函数string get_name();void set_name(string name);unsigned get_age();void set_age(unsigned age);//打印函数void print();private:string _name;unsigned _age;
};

Student.cpp

#include "Student.h"
using namespace std;Student::Student():_name("Empty"),_age(0)
{cout << "Student Constructor" << endl;
}Student::~Student()
{cout << "Student Destructor" << endl;
}string Student::get_name()
{return _name;
}void Student::set_name(string name)
{_name = name;
}unsigned Student::get_age()
{return _age;
}void Student::set_age(unsigned age)
{_age = age;
}void Student::print()
{cout << "name :" << _name << " age : " << _age << endl;
}

StudentRegFunc.h

#pragma once#include "Student.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}//------定义相关的全局函数------
//创建对象
int lua_create_new_student(lua_State* L);//get/set函数
int lua_get_name(lua_State* L);
int lua_set_name(lua_State* L);
int lua_get_age(lua_State* L);
int lua_set_age(lua_State* L);//打印函数
int lua_print(lua_State* L);//------注册全局函数供Lua使用------
static const luaL_Reg lua_reg_student_funcs[] = {{ "create", lua_create_new_student },{ "get_name", lua_get_name },{ "set_name", lua_set_name },{ "get_age", lua_get_age },{ "set_age", lua_set_age },{ "print", lua_print },{ NULL, NULL },
};int luaopen_student_libs(lua_State* L); 

StudentRegFunc.cpp

#include "StudentRegFunc.h"int lua_create_new_student(lua_State* L)
{//创建一个对象指针放到stack里,返回给Lua中使用Student** s = (Student**)lua_newuserdata(L, sizeof(Student*));*s = new Student();return 1;
}int lua_get_name(lua_State* L)
{//得到第一个传入的对象参数(在stack最底部)Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");//清空stacklua_settop(L, 0);//将数据放入stack中,供Lua使用lua_pushstring(L, (*s)->get_name().c_str());return 1;
}int lua_set_name(lua_State* L)
{//得到第一个传入的对象参数Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TSTRING);std::string name = lua_tostring(L, -1);(*s)->set_name(name);return 0;
}int lua_get_age(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");lua_pushinteger(L, (*s)->get_age());return 1;
}int lua_set_age(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TNUMBER);(*s)->set_age((unsigned)lua_tointeger(L, -1));return 0;
}int lua_print(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");(*s)->print();return 0;
}int luaopen_student_libs(lua_State* L)
{// 创建一张新的表,并把列表的函数注册进去luaL_newlib(L, lua_reg_student_funcs);return 1;
}

main.cpp

#include <iostream>
using namespace std;extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}#include "Student.h"
#include "StudentRegFunc.h"static const luaL_Reg lua_reg_libs[] = {{ "base", luaopen_base }, //系统模块{ "Student", luaopen_student_libs}, //模块名字Student,注册函数luaopen_student_libs{ NULL, NULL }
};int main(int argc, char* argv[])
{if (lua_State* L = luaL_newstate()) {//注册让lua使用的库const luaL_Reg* lua_reg = lua_reg_libs;for (; lua_reg->func; ++lua_reg) {luaL_requiref(L, lua_reg->name, lua_reg->func, 1);lua_pop(L, 1);}//加载脚本,如果出错,则打印错误if (luaL_dofile(L, "lua4.lua")) {cout << lua_tostring(L, -1) << endl;}lua_close(L);}else {cout << "luaL_newstate error !" << endl;}system("pause");return 0;
}

tolua

第二种方式是tolua,也就是tolua++
在cocos2dx中,基本都是用这种方式

//.h
class CMD_Data : public cocos2d::Ref
{
public:CMD_Data(unsigned short nlength);virtual ~CMD_Data();
public:void setMainCmdAndSubCmd(const unsigned short mainCmd, const unsigned short subCmd);unsigned short getMainCmd();unsigned short getSubCmd();
public:static CMD_Data *create(const int nLenth);//...
}//.cppvoid CMD_Data::setMainCmdAndSubCmd(const unsigned short mainCmd, const unsigned short  subCmd)
{m_wMainCmd = mainCmd;m_wSubCmd = subCmd;
}CMD_Data * CMD_Data::create(const int nLenth)
{CMD_Data * pData = new(std::nothrow) CMD_Data(nLenth);if (pData){//pData->autorelease();return pData;}CC_SAFE_DELETE(pData);return nullptr;
}unsigned short CMD_Data::getMainCmd()
{return m_wMainCmd;
}unsigned short CMD_Data::getSubCmd()
{return m_wSubCmd;
}

注册
.h

#pragma once
#include "base/ccConfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif
int register_all_Cmd_Data();

.cpp

int register_all_Cmd_Data()
{auto engine = LuaEngine::getInstance();ScriptEngineManager::getInstance()->setScriptEngine(engine);lua_State* tolua_S = engine->getLuaStack()->getLuaState();tolua_usertype(tolua_S, "CMD_Data");tolua_cclass(tolua_S, "CMD_Data", "CMD_Data", "cc.Node", nullptr);tolua_beginmodule(tolua_S, "CMD_Data");tolua_function(tolua_S, "create", tolua_Cmd_Data_create);tolua_function(tolua_S, "setCmdInfo", tolua_Cmd_Data_setMainCmdAndSubCmd);tolua_function(tolua_S, "getMainCmd", tolua_Cmd_Data_getMainCmd);tolua_function(tolua_S, "getSubCmd", tolua_Cmd_Data_getSubCmd);tolua_function(tolua_S, "getBufferLength", tolua_Cmd_Data_getBufferLength);tolua_function(tolua_S, "getCurIndex", tolua_Cmd_Data_getCurIndex);tolua_function(tolua_S, "setSendMessageLength", tolua_Cmd_Data_setSendMessageLength);tolua_endmodule(tolua_S);std::string typeName = typeid(CMD_Data).name();g_luaType[typeName] = "CMD_Data";g_typeCast["CMD_Data"] = "CMD_Data";return 1;
}int tolua_Cmd_Data_create(lua_State* tolua_S)
{int argc = lua_gettop(tolua_S);CMD_Data *data = nullptr;if (argc == 2){int nLength = lua_tointeger(tolua_S, 2);data = CMD_Data::create(nLength);}else{CCLOG("error CMD_Data create");}int nID = (data) ? data->_ID : -1;int *pLuaID = (data) ? &data->_luaID : nullptr;toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)data, "Cmd_Data");return 1;
}int tolua_Cmd_Data_setMainCmdAndSubCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){int argc = lua_gettop(tolua_S);if (argc == 3){unsigned short mainCmd = (unsigned short)lua_tointeger(tolua_S, 2);unsigned short subCmd = (unsigned short)lua_tointeger(tolua_S, 3);cobj->setMainCmdAndSubCmd(mainCmd, subCmd);}}return 0;
}int tolua_Cmd_Data_getMainCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){lua_pushinteger(tolua_S, cobj->getMainCmd());return 1;}return 0;
}int tolua_Cmd_Data_getSubCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){lua_pushinteger(tolua_S, cobj->getSubCmd());return 1;}return 0;
}

cocos2dx 生成工具

方便的是,cocos2dx提供了一套转换的工具。

在cocos2dx引擎目录下有个tools的目录,里面有tolua的文件夹。

它里面的大概结构如下

在这里插入图片描述

可以看得出来,cocos2dx本身的类都是用这个方法去实现的。

随便打开一个ini文件

[cocos2dx_ui]
# the prefix to be added to the generated functions. You might or might not use this in your own
# templates
prefix = cocos2dx_ui# create a target namespace (in javascript, this would create some code like the equiv. to `ns = ns || {}`)
# all classes will be embedded in that namespace
target_namespace = ccui# the native namespace in which this module locates, this parameter is used for avoid conflict of the same class name in different modules, as "cocos2d::Label" <-> "cocos2d::ui::Label".
cpp_namespace = cocos2d::uiandroid_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/include
android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/%(clang_lib_version)s/clang/%(clang_version)s/include
clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/androidcocos_flags = -DANDROIDcxxgenerator_headers = # extra arguments for clang
extra_arguments = %(android_headers)s %(clang_headers)s %(cxxgenerator_headers)s %(cocos_headers)s %(android_flags)s %(clang_flags)s %(cocos_flags)s %(extra_flags)s # what headers to parse
headers = %(cocosdir)s/cocos/ui/CocosGUI.h# what classes to produce code for. You can use regular expressions here. When testing the regular
# expression, it will be enclosed in "^$", like this: "^Menu*$".
classes = Helper Widget Layout Button CheckBox ImageView Text TextAtlas TextBMFont LoadingBar Slider TextField ScrollView ListView PageView LayoutParameter LinearLayoutParameter RelativeLayoutParameter Rich.* HBox VBox RelativeBox Scale9Sprite EditBox LayoutComponent AbstractCheckButton RadioButton RadioButtonGroup TabControl TabHeader# what should we skip? in the format ClassName::[function function]
# ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also
# regular expressions, they will not be surrounded by "^$". If you want to skip a whole class, just
# add a single "*" as functions. See bellow for several examples. A special class name is "*", which
# will apply to all class names. This is a convenience wildcard to be able to skip similar named
# functions from all classes.skip = *::[^visit$ copyWith.* onEnter.* onExit.* ^description$ getObjectType .*HSV onTouch.* onAcc.* onKey.* onRegisterTouchListener ccTouch.* (g|s)etDelegate],Widget::[addTouchEventListener addClickEventListener addCCSEventListener],LayoutParameter::[(s|g)etMargin],RichText::[setTagDescription removeTagDescription setOpenUrlHandler]rename_functions = rename_classes =# for all class names, should we remove something when registering in the target VM?
remove_prefix = # classes for which there will be no "parent" lookup
classes_have_no_parents = Helper# base classes which will be skipped when their sub-classes found them.
base_classes_to_skip =# classes that create no constructor
# Set is special and we will use a hand-written constructor
abstract_classes = Helper AbstractCheckButton# Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'.
script_control_cpp = no

prefix : 输出的前缀,会连接到tolua类型的函数名之前,例如 int cocos2dx_ui_xxx(lua_State* tolua_S);

target_namespace : 所有生成的类都属于这个表下 例如这个里面的 ccui.xxx

cpp_namespace : C++中的命名空间,自动生成的代码中会加上这个命名空间

android_headers : 这是安卓编译的一些指令,不需要修改,照抄就行

android_flags : 这是安卓编译的一些指令,不需要修改,照抄就行

clang_headers : 这是Clang的编译指令,不需要修改,照抄就行

cocos_flags : 这是Clang的编译指令,不需要修改,照抄就行

cocos_headers: cocos的头文件搜索目录

cocos_flags:照抄

cxxgenerator_headers : 不管

extra_arguments : 所有文件的搜索路径

headers:这是需要解析的头文件 会从这个文件中识别所有include的头文件,并解析其中的类, 可以填多个文件 比如自己的文件的需要引用的头文件

classes:需要生成哪些类的接口,这里支持正则表达式

skip:跳过哪些类和函数,支持正则表达式,可以借鉴cocos的配置文件

rename_functions:重命名函数

rename_classes:重命名类

abstract_classes:哪些类没有创建构造函数,需要手动重写构造函数

script_control_cpp:不管,一般都是no

可以生成自己的一个配置文件。

然后看下同样目录下的genbindings.py文件

在这里插入图片描述

需要将自己的ini文件填入进去。

然后运行这个python文件,便会自动生成。

一般如下

在这里插入图片描述

手写调用

有人会说,为啥cocos里面还有类似

在这里插入图片描述

首先,工具脚本不是万能的,有些无法导出,例如Lambda表达式,例如某些回调函数。

void GameNetWorkManager::resumSocketByIp(const int socketMark, const std::string &serverIp, const int serverPort, const std::function<void(bool)> &callback)
{callback(m_socketManage->resumSocket(socketMark,serverIp,serverPort));
}

比如这个方法。

无法生成,我们就需要手写

int tolua_GameNetWorkManager_resumSocket(lua_State* tolua_S)
{int argc = 0;GameNetWorkManager* cobj = nullptr;bool ok = true;#if COCOS2D_DEBUG >= 1tolua_Error tolua_err;
#endif#if COCOS2D_DEBUG >= 1if (!tolua_isusertype(tolua_S, 1, "GameNetWorkManager", 0, &tolua_err)) goto tolua_lerror;
#endifcobj = (GameNetWorkManager*)tolua_tousertype(tolua_S, 1, 0);#if COCOS2D_DEBUG >= 1if (!cobj){tolua_error(tolua_S, "invalid 'cobj' in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}
#endifargc = lua_gettop(tolua_S) - 1;if (argc == 2){int arg1;ok &= luaval_to_int32(tolua_S, 2, (int *)&arg1, "GameNetWorkManager:resumSocket");
#if COCOS2D_DEBUG >= 1if (!toluafix_isfunction(tolua_S, 3, "LUA_FUNCTION", 0, &tolua_err)){goto tolua_lerror;}
#endifint handler = (toluafix_ref_function(tolua_S, 3, 0));if (!ok){tolua_error(tolua_S, "invalid arguments in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}cobj->resumSocket(arg1,[=](bool resum){LuaStack* stack = LuaEngine::getInstance()->getLuaStack();stack->pushBoolean(resum);stack->executeFunctionByHandler(handler, 1);stack->clean();return 0;});ScriptHandlerMgr::getInstance()->addCustomHandler((void*)cobj, handler);lua_settop(tolua_S, 1);return 1;}else if (argc == 4){int arg1;std::string arg2;int arg3;ok &= luaval_to_int32(tolua_S, 2, (int *)&arg1, "GameNetWorkManager:resumSocket");ok &= luaval_to_std_string(tolua_S, 3, &arg2, "GameNetWorkManager:resumSocket");ok &= luaval_to_int32(tolua_S, 4, (int *)&arg3, "GameNetWorkManager:resumSocket");
#if COCOS2D_DEBUG >= 1if (!toluafix_isfunction(tolua_S, 5, "LUA_FUNCTION", 0, &tolua_err)){goto tolua_lerror;}
#endifint handler = (toluafix_ref_function(tolua_S, 5, 0));if (!ok){tolua_error(tolua_S, "invalid arguments in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}cobj->resumSocketByIp(arg1, arg2, arg3, [=](bool resum){LuaStack* stack = LuaEngine::getInstance()->getLuaStack();stack->pushBoolean(resum);stack->executeFunctionByHandler(handler, 1);stack->clean();return 0;});ScriptHandlerMgr::getInstance()->addCustomHandler((void*)cobj, handler);lua_settop(tolua_S, 1);return 1;}return 0;
#if COCOS2D_DEBUG >= 1tolua_lerror:tolua_error(tolua_S, "#ferror in function 'tolua_GameNetWorkManager_resumSocket'.", &tolua_err);
#endifreturn 0;
}

最后

如果需要深入了解Lua,强烈建议阅读《lua设计与实现》。

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

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

相关文章

【Jenkins】rpm方式安装Jenkins(2.401,jdk版本17)

目录 【Jenkins】rpm方式安装Jenkins 1、主机初始化 2、软件要求 RPM包安装的内容 配置文件说明 3、web操作 【Jenkins】rpm方式安装Jenkins 1、主机初始化 [rootlocalhost ~]# hostname jenkins[rootlocalhost ~]# bash[rootjenkins ~]# systemctl stop firewalld[roo…

YOLOv8教程系列:三、K折交叉验证——让你的每一份标注数据都物尽其用(yolov8目标检测+k折交叉验证法)

YOLOv8教程系列&#xff1a;三、K折交叉验证——让你的每一份标注数据都物尽其用&#xff08;yolov8目标检测k折交叉验证法&#xff09; 0.引言 k折交叉验证&#xff08;K-Fold Cross-Validation&#xff09;是一种在机器学习中常用的模型评估技术&#xff0c;用于估计模型的性…

Java详解编译型和解释型语言

在计算机的高级编程语言类型分为两种&#xff0c;分别是编译型和解释型&#xff0c;而Java既有编译型又有解释型 什么是编译型&#xff1f;什么是解释型&#xff1f; 字面上来说编译和解释都有‘翻译’的意思&#xff0c;而她们两个的区别是‘翻译’的时机不同&#xff0c;什…

Python采集电商平台泳衣数据进行可视化分析

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: python 3.8 解释器 pycharm 编辑器 模块使用: 第三方模块 需要安装 requests —> 发送 HTTP请求 内置模块 不需要安装 csv —> 数据处理中经常会用到的一种文件格式 第三方模块安装&#xff1a…

实验五 Linux 内核的安装与加载

【实验目的】 掌握 uboot 的使用方法&#xff0c;能够使用 uboot 安装和加载内核 【实验环境】 ubuntu 14.04 发行版FS4412 实验平台 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行&#xff0c;以“#”开头的命令表 示在开发板下执行 【实验步骤】 …

计算机视觉 -- 图像分割

文章目录 1. 图像分割2. FCN2.1 语义分割– FCN &#xff08;Fully Convolutional Networks&#xff09;2.2 FCN--deconv2.3 Unpool2.4 拓展–DeconvNet 3. 实例分割3.1 实例分割--Mask R-CNN3.2 Mask R-CNN3.3 Faster R-CNN与 Mask R-CNN3.4 Mask R-CNN&#xff1a;Resnet1013…

ES搭建集群

一、创建 elasticsearch-cluster 文件夹 创建 elasticsearch-7.8.0-cluster 文件夹&#xff0c;在内部复制三个 elasticsearch 服务。 然后每个文件目录中每个节点的 config/elasticsearch.yml 配置文件 node-1001 节点 #节点 1 的配置信息&#xff1a; #集群名称&#xff0…

【数据备份、恢复、迁移与容灾】上海道宁与云祺科技为企业用户提供云数据中心容灾备份解决方案

云祺容灾备份系统支持 主流虚拟化环境下的虚拟机备份 提供对云基础设施 云架构平台以及 应用系统的全方位数据保护 云祺容灾备份系统规范功能 增强决策能力 高效恢复数据至可用状态 有效降低恢复成本 更大限度减少业务中断时间 保障业务可访问性 开发商介绍 成都云祺…

LSTM数学计算公式

LSTM&#xff08;长短期记忆网络&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;常用于处理时间序列相关的任务。下面将简要介绍LSTM的数学推导和公式模型。 在训练一般神经网络模型时&#xff0c;通常用,其中W为权重&#xff0c;X为输入&#…

算法通关村第九关——中序遍历与搜索树

1 中序遍历和搜索树原理 二叉搜索树按照中序遍历正好是一个递增序列。其比较规范的定义是&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点的值均小于它的根节点的值&#xff1b;若它的右子树不为空&#xff0c;则右子树所有节点的值均大于它的根节点的值&…

【网络层协议】ARP攻击与欺骗常见的手段以及工作原理

个人主页&#xff1a;insist--个人主页​​​​​​ 本文专栏&#xff1a;网络基础——带你走进网络世界 本专栏会持续更新网络基础知识&#xff0c;希望大家多多支持&#xff0c;让我们一起探索这个神奇而广阔的网络世界。 目录 一、ARP攻击的常见手段 第一种&#xff1a;IP…

【健康医疗】Axure用药提醒小程序原型图,健康管理用药助手原型模板

作品概况 页面数量&#xff1a;共 20 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;健康管理&#xff0c;用药助手 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「用药提醒」小程序原型图…

Spring Boot 知识集锦之actuator监控端点详解

文章目录 0.前言1.参考文档2.基础介绍默认支持的端点 3.步骤3.1. 引入依赖3.2. 配置文件3.3. 核心源码 4.示例项目5.总结 0.前言 背景&#xff1a; 一直零散的使用着Spring Boot 的各种组件和特性&#xff0c;从未系统性的学习和总结&#xff0c;本次借着这个机会搞一波。共同学…

Android NDK JNI与Java的相互调用

一、Jni调用Java代码 jni可以调用java中的方法和java中的成员变量,因此JNIEnv定义了一系列的方法来帮助我们调用java的方法和成员变量。 以上就是jni调用java类的大部分方法,如果是静态的成员变量和静态方法,可以使用***GetStaticMethodID、CallStaticObjectMethod等***。就…

『C语言』数据在内存中的存储规则

前言 小羊近期已经将C语言初阶学习内容与铁汁们分享完成&#xff0c;接下来小羊会继续追更C语言进阶相关知识&#xff0c;小伙伴们坐好板凳&#xff0c;拿起笔开始上课啦~ 一、数据类型的介绍 我们目前已经学了基本的内置类型&#xff1a; char //字符数据类型 short …

SpeedBI数据可视化工具:浏览器上做分析

SpeedBI数据分析云是一种在浏览器上进行数据可视化分析的工具&#xff0c;它能够将数据以可视化的形式呈现出来&#xff0c;并支持多种数据源和图表类型。 所有操作&#xff0c;均在浏览器上进行 在浏览器中打开SpeedBI数据分析云官网&#xff0c;点击【免费使用】进入&#…

微服务(多级缓存)

多级缓存 1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈Redis缓存失效时&…

SpringCloud学习笔记(二)_Eureka注册中心

一、Eureka简介 Eureka是一项基于REST&#xff08;代表性状态转移&#xff09;的服务&#xff0c;主要在AWS云中用于定位服务&#xff0c;以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka Server。Eureka还带有一个基于Java的客户端组件Eureka Client&#xff…

发布 net 项目 到 Docker

背景 因为发布到 centOS8 使用 screen -S 可以&#xff0c;想开机自启 使用 nohup 命令有启动不起来。环境问题不好找&#xff0c;就想尝试用 docker 运行 步骤 在生成的 Dockerfile 文件里增加修改时区指令 因为我们用的都是北京时间所以 创建镜像的时候就调整好 #设置时间…

B站视频码率用户上传视频的视频码率

一般来说&#xff0c;B站用户可以根据自己的视频内容和需求来选择视频的码率&#xff0c;但以下是一些常见的视频码率范围&#xff0c;供用户参考&#xff1a; 标清&#xff08;SD&#xff09;&#xff1a; 码率范围可能在500 Kbps至1.5 Mbps左右&#xff0c;适用于480p的分辨率…