You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sol3中如何检测usertype是否存在 实现创建或获取用户类型逻辑

问题根因

Sol3 原生的new_usertype接口默认不会做存在性校验,只要调用就会在Lua环境中覆盖同名的已注册用户类型元表,所以第二次调用时第一次绑定的testFunction1会被直接清空,只剩第二次绑定的testFunction2。

实现方案

Sol3 没有内置同名usertype复用的接口,可以自行实现通用的CreateOrGetUserType辅助函数,逻辑是注册前先检查对应名称的类型是否已经存在,存在则直接返回已有的usertype实例,不存在才走新建逻辑。

辅助函数实现代码:

#include <sol/sol.hpp>
#include <string>
#include <utility>

template<typename T, typename... CtorArgs>
sol::usertype<T> CreateOrGetUserType(sol::state& lua, const std::string& type_name, CtorArgs&&... args)
{
    // 从全局表查询同名对象
    sol::object existing_type = lua.globals()[type_name];
    // 判断是否是已经注册的目标C++类型对应的usertype
    if (existing_type.valid() && existing_type.is<sol::usertype<T>>())
    {
        return existing_type.as<sol::usertype<T>>();
    }
    // 不存在则新建注册
    return lua.new_usertype<T>(type_name, std::forward<CtorArgs>(args)...);
}

使用时直接替换原有new_usertype调用即可,完全匹配预期写法:

sol::state _state;

void Func1()
{
    auto userType1 = CreateOrGetUserType<Test>(_state, "Test", sol::constructors<Test()>());
    userType1["testFunction1"] = &test1;
}

void Func2()
{
    auto userType2 = CreateOrGetUserType<Test>(_state, "Test", sol::constructors<Test()>());
    userType2["testFunction2"] = &test2;
}

int main()
{
    _state.open_libraries(sol::lib::base);
    Func1();
    Func2();
    // 脚本侧可正常调用两个方法
    _state.script(R"(
        local inst = Test.new()
        inst:testFunction1()
        inst:testFunction2()
    )");
    return 0;
}
注意事项
  • 首次注册时传入的构造函数、基类绑定、元方法(比如__index、__gc)等核心类型配置会永久生效,后续获取已存在usertype时传入的同类配置不会覆盖原有设置,不会产生冲突
  • 不管是第几次拿到usertype实例,通过[]赋值绑定的方法、属性都会追加到类型定义上,不会清除之前绑定的成员
  • 如果需要把usertype注册到自定义模块表而非全局环境,只需要把辅助函数中查询lua.globals()的逻辑替换为查询对应的父表对象即可

内容的提问来源于stack exchange,提问作者Shadow fiend

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:27:14