当前位置: 首页 > news >正文

# 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设计与实现》。

相关文章:

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

C 调用lua 基础调用 再来温习一下 myName “beauty girl” C想要获取myName的值&#xff0c;根据规则&#xff0c;它需要把myName压入栈中&#xff0c;这样lua就能看到&#xff1b;lua从堆栈中获取myName的值&#xff0c;此时栈顶为空&#xff1b;lua拿着myName去全局表中查…...

机器人焊接生产线参数监控系统理解需求

机器人焊接生产线参数监控系统是以参数来反映系统状态并以直观的方式表现 出来&#xff0c;及时了解被监视对象的状态和状态的变化情况。其主要目标是为了达到减少 生产线的处理时间&#xff0c;降低故障率&#xff0c;缩短故障排除时间&#xff0c;从而提高生产线的生产效率 …...

前端基础(ES6 模块化)

目录 前言 复习 ES6 模块化导出导入 解构赋值 导入js文件 export default 全局注册 局部注册 前言 前面学习了js&#xff0c;引入方式使用的是<script s"XXX.js">&#xff0c;今天来学习引入文件的其他方式&#xff0c;使用ES6 模块化编程&#xff0c;…...

第七章,文章界面

7.1添加个人专栏 <template><div class="blog-container"><div class="blog-pages"><!-- 用于渲染『文章列表』和『文章内容』 --><router-view/><div class="col-md-3 main-col pull-left"><div cla…...

HJ102 字符统计

描述 输入一个只包含小写英文字母和数字的字符串&#xff0c;按照不同字符统计个数由多到少输出统计结果&#xff0c;如果统计的个数相同&#xff0c;则按照ASCII码由小到大排序输出。 数据范围&#xff1a;字符串长度满足 1≤len(str)≤1000 1≤len(str)≤1000 输入描述&a…...

Maven聚合项目(微服务项目)创建流程,以及pom详解

1、首先创建springboot项目作为父项目 只留下pom.xml 文件&#xff0c;删除src目录及其他无用文件 2、创建子项目 子项目可以是maven项目&#xff0c;也可以是springboot项目 3、父子项目关联 4、父项目中依赖管理 <?xml version"1.0" encoding"UTF-8&qu…...

Android OkHttp 源码浅析一

演进之路:原生Android框架不好用 ---- HttpUrlConnect 和 Apache HTTPClient 第一版 底层使用HTTPURLConnect 第二版 Square构建 从Android4.4开始 基本使用: val okhttp OkHttpClient()val request Request.Builder().url("http://www.baidu.com").buil…...

【Redis】——Redis基础的数据结构以及应用场景

什么是redis数据库 Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。&#xff0c;Redis 还支持 事务 、持久化、Lua 脚本、多种集群方案&#xff08;主…...

SpringBoot+WebSocket搭建多人在线聊天环境

一、WebSocket是什么&#xff1f; WebSocket是在单个TCP连接上进行全双工通信的协议&#xff0c;可以在服务器和客户端之间建立双向通信通道。 WebSocket 首先与服务器建立常规 HTTP 连接&#xff0c;然后通过发送Upgrade标头将其升级为双向 WebSocket 连接。 WebSocket使得…...

推荐适用于不同规模企业的会计软件:选择最适合您企业的解决方案

高效的会计软件不仅可以协助企业进行财务管理&#xff0c;做出科学的财务决策&#xff0c;还可以对企业数字化转型提供助力。不同规模的企业需要根据其特定需求选择适合的会计软件。那么有什么适合不同规模企业的会计软件推荐吗&#xff1f; 小型企业的选择 对于小型企业而言&…...

Apache Zookeeper架构和选举机制

ZooKeeper是一个开源的分布式协调服务,旨在解决分布式系统中的一致性、配置管理、领导者选举等问题。它由Apache软件基金会维护,是Hadoop生态系统的一部分,被广泛用于构建高可用、可靠和具有一致性的分布式应用程序和服务。 ZooKeeper提供了一个层次化的命名空间,类似于文…...

车联网TCU USB的配置和使用

1 usb_composition命令 # cat /sbin/usb/target # cd /sys/class/android_usb/android0 # cat functions console shows that QCOM’s default configuration Usage: usb_composition [Pid] [HSIC] [PERSISTENT] [IMMEDIATE] [FROM_ADBD] usb_composition 9025 n y y Then this…...

Linux系统USB摄像头测试程序(三)_视频预览

这是在linux上usb摄像头视频预览程序&#xff0c;此程序用到了ffmpeg、sdl2、gtk3组件&#xff0c;程序编译之前应先安装他们。 #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <zconf.h> …...

目标检测任务数据集的数据增强中,图像水平翻转和xml标注文件坐标调整

需求&#xff1a; 数据集的数据增强中&#xff0c;有时需要用到图像水平翻转的操作&#xff0c;图像水平翻转后&#xff0c;对应的xml标注文件也需要做坐标的调整。 解决方法&#xff1a; 使用pythonopencvimport xml.etree.ElementTree对图像水平翻转和xml标注…...

系统架构的演变

随着互联网的发展&#xff0c;网站应用的规模不断扩大&#xff0c;常规的应用架构已无法应对&#xff0c;分布式服务架构以及微服务架构势在必行&#xff0c;必需一个治理系统确保架构有条不紊的演进。 单体应用架构 Web应用程序发展的早期&#xff0c;大部分web工程(包含前端…...

IDC发布《亚太决策支持型分析数据平台评估》报告,亚马逊云科技位列“领导者”类别

日前&#xff0c;领先的IT市场研究和咨询公司IDC发布《2023年亚太地区&#xff08;不含日本&#xff09;决策支持型分析数据平台供应商评估》1报告&#xff0c;亚马逊云科技位列“领导者”类别。IDC认为&#xff0c;亚马逊云科技在解决方案的协同性、敏捷性、完整性、及时性、经…...

C#之OpenFileDialog创建和管理文件选择对话框

OpenFileDialog 是用于图形用户界面&#xff08;GUI&#xff09;编程的一个类&#xff0c;它用于显示一个对话框&#xff0c;允许用户选择要打开的文件。在需要用户加载或打开文件的应用程序中&#xff08;如文本编辑器、图像查看器或文档处理器&#xff09;&#xff0c;这是一…...

Java中使用MongoTemplate 简单操作MongoDB

Autowired private MongoTemplate mongoTemplate; User&#xff1a;封装的对象 插入&#xff1a;mongoTemplate.insert(user); 根据id查询&#xff1a;mongoTemplate.findById(id, User.class); 查询所有&#xff1a;mongoTemplate.findAll(User.class); 条件查询&#…...

[Mac软件]Pixelmator Pro 3.3.12 专业图像编辑中文版

Pixelmator Pro是专为Mac设计的功能强大&#xff0c;美观且易于使用的图像编辑器。借助广泛的专业级无损图像编辑工具&#xff0c;Pixelmator Pro可使您发挥出最佳的照片效果&#xff0c;创建华丽的构图和设计&#xff0c;绘制&#xff0c;绘画&#xff0c;应用令人惊叹的效果&…...

吴恩达 GPT Prompting 课程

Prompting Guidelines 目录 Guidelines for PromptingPrompting Principles Principle 1: Write clear and specific instructions1.1: Use delimiters to clearly indicate distinct parts of the input1.2: Ask for a structured output1.3: Ask the model to check whether …...

gpt3.5写MATLAB代码剪辑视频,使之保留画面ROI区域

% 输入和输出文件名 inputVideoFile input_video.mp4; outputVideoFile output_video.mp4;% 创建 VideoReader 和 VideoWriter 对象 videoReader VideoReader(inputVideoFile); outputVideo VideoWriter(outputVideoFile, MPEG-4); outputVideo.FrameRate videoReader.Fra…...

设计模式二十一:状态模式(State Pattern)

一个对象的内部状态发生变化时&#xff0c;允许对象改变其行为。这种模式使得一个对象看起来好像在运行时改变了它的类&#xff0c;主要目的是将状态的行为从主要对象中分离出来&#xff0c;使得主要对象不必包含所有状态的逻辑&#xff0c;而是将每个状态的行为封装在独立的类…...

【校招VIP】产品思维能力之产品设计

考点介绍&#xff1a; 对于产品经理来说最重要的就是产品思维&#xff0c;而拥有一个好的产品思维需要做到以下三点&#xff1a; 1、把握关键点的能力 2、出方案&#xff0c;协调资源&#xff0c;说服团队把资源倾斜到关键点上的能力 3、评估关键点进展程度的能力 『产品思维能…...

微信小程序卡片横向滚动竖图

滚动并不是使用swiper&#xff0c;该方式使用的是scroll-view实现 Swiper局限性太多了&#xff0c;对竖图并不合适 从左往右滚动图片示例 wxml代码&#xff1a; <view class"img-x" style"margin-top: 10px;"><view style"margin: 20rpx;…...

SpringBoot项目(支付宝整合)——springboot整合支付宝沙箱支付 从极简实现到IOC改进

目录 引出git代码仓库准备工作支付宝沙箱api内网穿透 [natapp.cn](https://natapp.cn/#download) springboot整合—极简实现版1.导包配置文件2.controller层代码3.进行支付流程4.支付成功回调 依赖注入的改进1.整体结构2.pom.xml文件依赖3.配置文件4.配置类&#xff0c;依赖注入…...

【AIGC】一款离线版的AI智能换脸工具V2.0分享(支持图片、视频、直播)

随着人工智能技术的爆发&#xff0c;AI不再局限于大语言模型&#xff0c;在图片处理方面也有非常大的进步&#xff0c;其中AI换脸也是大家一直比较感兴趣的&#xff0c;但这个技术的应用一直有很大的争议。 今天给大家分享一个开源你的AI换脸工具2.0&#xff0c;只需要一张所需…...

管理类联考——逻辑——真题篇——按知识分类——汇总篇——一、形式逻辑——选言——相容选言——或

文章目录 第五章 选言命题:相容选言-或;不相容选言-要么要么第一节 选言-相容选言-或-推结论-A或B为真,则非A→B,非B→A(否一则肯一)真题(2010-28)-选言-相容选言-或-推结论-(1)A或B为真,A为假:得B为真(否一则肯一);真题(2012-29)-选言-相容选言-或-推结论-(1)…...

Git如何操作本地分支仓库?

基本使用TortoiseGit 操作本地仓库(分支) 分支的概念 几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来&#xff0c;避免影响开发主线。多线程开发,可以同时开启多个任务的开发&#xff0c;多个任务之间互不影响。 为何要…...

WPS右键新建没有docx pptx xlsx 修复

解决wps右键没有新建文档的问题 右键没有新建PPT和Excel 1 wps自带的修复直接修复没有用 以上不管咋修复都没用 2 先编辑注册表 找到 HKEY_CLASSES_ROOT CTRLF搜文件扩展名 pptx docx xlsx 新建字符串 三种扩展名都一样操作 注册表编辑之后再次使用wps修复 注册组件&am…...

【巧学C++之西游篇】No.2 --- C++闹天宫,带着“重载“和“引用“

文章目录 前言&#x1f31f;一、函数重载&#x1f30f;1.1.函数重载概念&#x1f30f;1.2.C支持函数重载的原理 -- 名字修饰 &#x1f31f;二、引用&#x1f30f;2.1.引用的概念&#x1f30f;2.2.引用特性&#x1f30f;2.3.常引用&#x1f30f;2.4.使用场景&#x1f30f;2.5.传…...

【HarmonyOS】实现将pcm音频文件进行编码并写入文件(API6 Java)

【关键字】 音频编码、管道模式、createEncoder 【写在前面】 在使用API6开发HarmonyOS应用时&#xff0c;如何将pcm源文件进行编码并写入文件&#xff0c;最后生成aac文件&#xff0c;本文直接附上主要代码开发步骤供大家参考。 【主要功能代码】 import ohos.media.codec.…...

KaiwuDB CTO 魏可伟:回归用户本位,打造“小而全”的数据库

8月16日&#xff0c;KaiwuDB 受邀亮相第十四届中国数据库技术大会 DTCC 2023。KaiwuDB CTO 魏可伟接受大会主办方的采访&#xff0c;双方共同围绕“数据库架构演进、内核引擎设计以及不同技术路线”展开深度探讨。 以下是采访的部分实录 ↓↓↓ 40 多年前&#xff0c;企业的数…...

行业追踪,2023-08-22

自动复盘 2023-08-22 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…...

浏览器安装selenium驱动,以Microsoft Edge安装驱动为例

Selenium是一个用于Web应用程序测试的自动化工具。它可以直接在浏览器中运行&#xff0c;模拟真实用户对浏览器进行操作。利用selenium&#xff0c;可以驱动浏览器执行特定的动作&#xff0c;比如&#xff1a;点击、下拉等等&#xff0c;还可以获取浏览器当前呈现的页面的源代码…...

边缘计算网关是如何提高物联网的效率的?

随着物联网的持续发展&#xff0c;物联网应用的丰富和规模的扩大&#xff0c;带来了海量的数据处理、传输和计算需求。 传统的“数据中央处理”模式越来越难以适应物联网的扩展速度&#xff0c;在这一趋势下&#xff0c;边缘计算在物联网系统的部署运营中就发挥出了显著的增效…...

AWVS安装~Windows~激活

目录 1.下载安装包 2.双击acunetix_15.1.221109177.exe进行安装 3.配置C:\Windows\System32\drivers\etc\hosts 4.复制wvsc.exe到C:\Program Files (x86)\Acunetix\15.1.221109177下 5.复制license_info.json与wa_data.dat到C:\ProgramData\Acunetix\shared\license下&…...

ATFX汇市:杰克逊霍尔年会降至,鲍威尔或再发鹰派言论

环球汇市行情摘要—— 昨日&#xff0c;美元指数下跌0.11%&#xff0c;收盘在103.33点&#xff0c; 欧元升值0.22%&#xff0c;收盘价1.0898点&#xff1b; 日元贬值0.58%&#xff0c;收盘价146.23点&#xff1b; 英镑升值0.18%&#xff0c;收盘价1.2757点&#xff1b; 瑞…...

Zipkin开源的分布式链路追踪系统

Zipkin是一款开源的分布式链路追踪系统,主要功能包括: 1. 采集跟踪数据 - Zipkin client库负责收集并上报各服务的请求信息。 2. 存储跟踪数据 - 存储层默认采用Zipkin自带的基于内存的快速存储,也支持整合MySQL、Cassandra等外部存储。 3. 查询接口 - 提供RESTful API进行跟…...

java 项目运行时,后端控制台出现空指针异常---java.lang.NullPointerException

项目场景&#xff1a; 提示&#xff1a;这里简述项目背景&#xff1a; 场景如下&#xff1a; java 项目运行时&#xff0c;后端控制台出现如下图所示报错信息&#xff1a;— 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; java 项目运行时&#xff0c;后…...

模型数据处理-数据放入 session和@ModelAttribute 实现 prepare 方法详细讲解

&#x1f600;前言 本文详细讲解了模型数据处理-数据放入 session和ModelAttribute 实现 prepare 方法详细讲解 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c…...

关于android studio 几个简单的问题说明

自信是成功的第一步。——爱迪生 1. android studio 如何运行不同项目是否要更换不同的sdk 和 gradle 2.编译Gradle总是错误为什么 3.如何清理android studio 的缓存 4. 关于android Studio中的build 下面的rebuild project...

angular常用命令

文章目录 1. 创建新项目&#xff1a;2. 生成组件&#xff1a;3. 生成模块&#xff1a;4. 生成服务&#xff1a;5. 运行项目&#xff1a;6. 构建项目&#xff1a;其他 在 Angular 开发中&#xff0c;以下是一些常用的 Angular CLI 命令&#xff1a; 1. 创建新项目&#xff1a; …...

uni-app打包后安卓不显示地图及相关操作详解

新公司最近用uni-app写app&#xff0c;之前的代码有很多问题&#xff0c;正好趁着改bug的时间学习下uni-app。 问题现象&#xff1a; 使用uni-app在浏览器调试的时候&#xff0c;地图是展示的&#xff0c;但是打包完成后&#xff0c;在app端是空白的。咱第一次写app&#xff…...

elelementui组件

一、按钮 1、按钮样式 使用type、plain、round和circle属性来定义 Button 的样式。 2、主要代码 <el-row><el-button>默认按钮</el-button><el-button type"primary">主要按钮</el-button><el-button type"success">…...

什么是安全测试报告,怎么获得软件安全检测报告?

安全测试报告 软件安全测试报告&#xff1a;是指测试人员对软件产品的安全缺陷和非法入侵防范能力进行检查和验证的过程&#xff0c;并对软件安全质量进行整体评估&#xff0c;发现软件的缺陷与 bug&#xff0c;为开发人员修复漏洞、提高软件质量奠定坚实的基础。 怎么获得靠谱…...

JS中的Ajax

封装原生 Ajax 请求 在 JavaScript 中&#xff0c;可以通过封装原生的 Ajax 请求来进行与服务器的数据交互。下面是一个封装了原生 Ajax 请求的示例代码&#xff0c;以及对代码的详细注解。 1.简单的Ajax封装代码 <h2>ajax原生</h2><script>//1.创建xhr对象…...

ImportError: cannot import name ‘SQLDatabaseChain‘ from ‘langchain‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

npm、yarn和pnpm

1 node_modules安装方式 在npm3之前是以嵌套结构方式安装依赖包&#xff0c;存在两个问题&#xff1a; 依赖路径太长多个包依赖一个相同包时&#xff0c;本地磁盘会存储多个相同的包 npm3和yarn使用扁平化结构&#xff0c;node_modules变成所有包放在同一层级 注意&#xf…...

SparkSQL源码分析系列02-编译环境准备

本文主要描述一些阅读Spark源码环境的准备工作&#xff0c;会涉及到源码编译&#xff0c;插件安装等。 1. 克隆代码。 打开IDEA&#xff0c;在Git下的Clone中&#xff0c;输入 https://github.com/apache/spark&#xff0c;克隆代码到本地&#xff0c;CheckOut到目标版本Spar…...

【计算机网络】日志与守护进程

文章目录 日志日志的创建logmessage 函数日志左边部分实现日志右边部分实现 完整代码log.hpp(整体实现)err.hpp (错误信息枚举&#xff09; 守护进程PGID SID TTY 的介绍shell中控制进程组的方式结论 为什么要有守护进程存在&#xff1f;守护进程的创建使用守护进程的条件守护进…...