OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI 常见的函数详解(二)

news2024/9/19 8:21:59

引言

前面一篇文章OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI(一)介绍了NAPI的基础理论知识,今天重点介绍下NAPI中重要的函数。

一、Native 侧的NAPI的相关的C++函数

以下面一段代码为例介绍下主要函数的功能和用法。

napi_value MSLiteModelNapi::Init(napi_env env, napi_value exports) {
  napi_property_descriptor properties[] = {DECLARE_NAPI_FUNCTION("getInputs", GetInputs),
 DECLARE_NAPI_FUNCTION("predict", PredictAsync)};

  napi_property_descriptor staticProperty[] = {
    DECLARE_NAPI_STATIC_FUNCTION("loadModelFromFile", LoadMSLiteModelFromFile),
    DECLARE_NAPI_PROPERTY("Format", CreateFormatObject(env)),
    DECLARE_NAPI_PROPERTY("DataType", CreateDataTypeObject(env)),
    DECLARE_NAPI_PROPERTY("ThreadAffinityMode", CreateThreadAffinityModeObject(env)),
  };

  napi_value constructor = nullptr;
  napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);

  status = napi_create_reference(env, constructor, REFERENCE_CREATION_COUNT, &constructor_);

  status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);

  status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
  return exports;
}

1、DECLARE_NAPI_FUNCTION

宏接收两个参数:

  • name:是要定义的函数的名字。
  • func:是对应的函数实现。
    宏展开后,它创建了一个结构体(可能是napi_property_descriptor),该结构体包含了以下字段:
  • name:函数的名字。
  • method:函数的实现。
    其他一些字段被设置为nullptr或者默认值,这些可能涉及到函数的属性、 getter、setter、enumerator、data以及属性标志等。这个宏的主要作用是简化N-API函数的定义过程,使得开发者不需要手动填写所有的结构体字段,只需提供函数名和实现即可。
#define DECLARE_NAPI_FUNCTION(name, func)                                         \
    {                                                                             \
        (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \
    }

func是一个 C++ 函数,它被声明为 NAPI 函数 “func”。然后,这个函数被添加到导出的对象中,这样 JavaScript 代码就可以通过 require 函数引入并调用它。

2、DECLARE_NAPI_STATIC_FUNCTION

DECLARE_NAPI_STATIC_FUNCTION 宏用于声明一个静态函数,可以直接通过模块名直接调用。该函数将被导出为 NAPI 函数,这样 JavaScript 代码就可以通过 require 函数引入并调用它。其他与DECLARE_NAPI_FUNCTION大同小异。

#define DECLARE_NAPI_STATIC_FUNCTION(name, func)                                 \
    {                                                                            \
        (name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \
    }

选择使用 DECLARE_NAPI_STATIC_FUNCTION 还是 DECLARE_NAPI_FUNCTION 取决于你的函数是否需要与类的实例关联。如果你正在编写一个不需要类上下文的独立函数,应该使用静态函数。如果你正在实现一个类,并且函数是类的一部分,那么应该使用非静态函数。

napi_value MethodA(napi_env env, napi_callback_info info) {
    // 实现具体的函数逻辑
    // ...
    return nullptr;
}

NAPI_EXPORT NAPI_INIT() {
	...
    // 声明 NAPI 函数
    DECLARE_NAPI_STATIC_FUNCTION("methodA", MethodA);
    ...
}

3、DECLARE_NAPI_PROPERTY

宏在 NAPI(Node.js API)中用于声明一个属性,这个属性可以是静态的或者属于某个对象的实例。属性在 NAPI 中可以被视为只读或可写的数据成员,它们允许你将 C/C++ 中的变量或常量暴露给 JavaScript 代码。

#define DECLARE_NAPI_PROPERTY(name, val)\                                     
{                                                        \                                                        
(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr \
}

使用 DECLARE_NAPI_PROPERTY 宏时,你需要提供以下信息:

  • 属性名称:这是在 JavaScript 代码中访问该属性时使用的名称。
  • 获取函数:一个可选的函数,当 JavaScript 代码尝试读取属性时被调用。
  • 设置函数:一个可选的函数,当 JavaScript 代码尝试设置属性的值时被调用。
  • 属性值:对于常量属性,这是属性的初始值
#include <napi.h>

Napi::Value GetMyProperty(const Napi::CallbackInfo& info) {
    // 返回属性值
    return Napi::Value::From(info.Env(), 42);
}

void SetMyProperty(const Napi::CallbackInfo& info, const Napi::Value& value) {
    // 处理属性值的设置
    // 这里可以添加代码来处理 value 参数
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
    // 使用 DECLARE_NAPI_PROPERTY 宏声明属性
    DECLARE_NAPI_PROPERTY("MyProperty", GetMyProperty, SetMyProperty);
    
    // 将声明的属性添加到模块的导出对象中
    exports.Set("MyProperty", MyProperty);
    
    return exports;
}

NODE_API_MODULE(myaddon, Init)

4、DECLARE_NAPI_STATIC_PROPERTY

DECLARE_NAPI_PROPERTY 和 DECLARE_NAPI_STATIC_PROPERTY 是两个用于声明属性的宏,它们之间的主要区别在于属性的生命周期和作用域,DECLARE_NAPI_PROPERTY 用于声明一个与对象实例关联的属性,通常是可读写的,并且通过对象的实例来访问和修改;DECLARE_NAPI_STATIC_PROPERTY 用于声明一个静态属性,它属于类或模块,而不是某个特定的实例。静态属性通常是只读的,或者具有相同的getter和setter函数,这些函数不会依赖于对象的状态。

5、napi_define_class

Node.js API (NAPI) 中的一个函数,用于在 Node.js 环境中定义一个新的 JavaScript 函数,该函数可以创建一个对象的实例。这个函数通常用于将 C/C++ 中的类封装为 Node.js 模块中的构造函数,使得 JavaScript 代码可以通过这个构造函数创建对象实例,并调用其方法和访问其属性。

napi_status napi_define_class(napi_env env,
                            const char* class_name,
                            size_t constructor_name_count,
                            const napi_property_descriptor* property_descriptors,
                            napi_value constructor_function,
                            napi_value* constructor_name);

其中参数说明:

env:指向当前环境的指针。
class_name:新类名的字符串。
constructor_name_count:构造函数名称的数量,通常为 1。
property_descriptors:指向一个 napi_property_descriptor 数组的指针,该数组描述了类的属性和方法。
constructor_function:一个 napi_value,表示构造函数,当调用构造函数时,会调用指定的 JavaScript 函数。
constructor_name:一个 napi_value 数组,包含与 constructor_function 对应的名称。
napi_property_descriptor 结构体用于描述类的属性和方法,其原型如下:

typedef struct {
  const char* name;             // 属性或方法的名称
  napi_value getter;             // 获取器函数,如果属性是只读的,则设置为 NULL
  napi_value setter;             // 设置器函数,如果属性是只写的,则设置为 NULL
  napi_value method;            // 方法函数,如果属性不是方法,则设置为 NULL
  napi_value enum_value;        // 枚举值,通常设置为 NULL
  napi_value default_value;      // 默认值,通常设置为 NULL
} napi_property_descriptor;

OpenHarmony NAPI 提供了一种“包装”C ++类和实例的方法,以便 JS 应用可以调用类的构造函数和方法。

Node.js Node-API 中关于导出类对象的内容,参考链接 : https:// nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_object_wrap

NAPI 导出类对象流程

  • 通过napi_define_class定义一个 JS 类
  • 它包含了与 C++ 类对应的构造函数、静态属性、方法、实例属性和方法。
  • 通过napi_wrap将 C++ 实例绑定在 JS 对象中
  • 当 JS 代码调用构造函数时,构造函数回调会使用 napi_wrap 将一个新的 C++ 实例绑定在 JS 对象中,然后返回绑定的 C++ 实例。
  • 通过napi_unwrap获取作为调用目标的 C++ 实例
  • 当 JS 调用 C++ 类 的方法或属性时,会调用相应的 napi_callback C++ 函数。对于实例回调,napi_unwrap获取作为调用目标的 C++ 实例 。
    在这里插入图片描述

6、napi_create_reference 和 napi_get_reference_value、napi_delete_reference

napi_create_reference 用于创建对 JavaScript 对象的引用。这个引用可以用于在后续的 NAPI 调用中保持对象的生命周期,即使在对象不再被 JavaScript 代码直接引用时也不会被垃圾回收。当你在 C/C++ 代码中使用 NAPI 与 JavaScript 代码交互时,你可能需要在多个地方使用同一个 JavaScript 对象。为了确保这个对象在这些地方都被有效引用,你可以使用 napi_create_reference 来创建一个持久化的引用。这个引用可以通过一个整数值(通常称为引用句柄)来标识和操作。

napi_create_reference 函数的原型如下:

napi_status napi_create_reference(napi_env env, napi_value object, uint32_t initial_refcount, napi_ref* result);

参数说明:

  • env:指向当前环境的指针。
  • object:要创建引用的 JavaScript 对象。
  • initial_refcount:引用的初始引用计数。通常设置为 1,表示创建一个新引用。
  • result:指向 napi_ref 的指针,成功创建引用后,该位置将存储新引用的句柄。
#include <napi.h>

napi_value CreateObject(napi_env env, napi_callback_info info) {
    // 创建一个新的 JavaScript 对象
    napi_value object;
    napi_create_object(env, &object);

    // 创建一个持久化的引用
    napi_ref ref;
    napi_create_reference(env, object, 1, &ref);

    // 这里可以将 ref 用于后续的调用,以便在需要时重新获取对象

    // 返回创建的对象
    return object;
}

napi_value UseObjectReference(napi_env env, napi_callback_info info) {
    // 假设我们有一个有效的引用句柄
    napi_ref ref;

    // 从引用句柄获取对象
    napi_value object;
    napi_get_reference_value(env, ref, &object);

    // 使用对象...
    return nullptr;
}

使用 napi_create_reference 和 napi_get_reference_value 可以在 NAPI 函数之间共享和持久化 JavaScript 对象的引用,这在处理异步操作或跨多个调用共享资源时非常有用。需要注意的是,创建引用后,你需要负责管理引用的生命周期,包括在适当的时候使用 napi_delete_reference 来删除引用,以避免内存泄漏。

  • napi_get_reference_value() : 从napi_ref引用对象中取得napi_value
  • napi_delete_reference() :删除napi_ref引用对象

7、napi_set_named_property

用于在 JavaScript 对象上设置一个命名属性的值。napi_set_named_property 函数的原型如下:

napi_status napi_set_named_property(napi_env env,
                                 napi_value object,
                                 const char16_t* property_name,
                                 napi_value value);

参数说明:

  • env:指向当前 NAPI 环境的指针。
  • object:要设置属性的 JavaScript 对象。
  • property_name:一个以 UTF-16 编码的字符串,表示要设置的属性名。
  • value:要设置的属性值的 napi_value。
#include <napi.h>

napi_value SetObjectProperty(napi_env env, napi_callback_info info) {
    // 创建一个 JavaScript 对象
    napi_value obj;
    napi_create_object(env, &obj);

    // 创建一个属性值
    napi_value propValue;
    napi_create_string_utf8(env, "Hello, World!", NAPI_OK, &propValue);

    // 设置对象的属性
    const char16_t* propertyName = "exampleProperty";
    napi_status status = napi_set_named_property(env, obj, propertyName, propValue);
    if (status != napi_ok) {
        // 处理错误
        return nullptr;
    }

    // 返回创建的对象
    return obj;
}

SetObjectProperty 函数首先创建了一个空的 JavaScript 对象,然后创建了一个字符串值作为属性值。最后,使用 napi_set_named_property 函数将这个值设置为对象的 exampleProperty 属性。napi_set_named_property 是 NAPI 中用于对象属性操作的重要函数之一,它使得 C/C++ 代码能够动态地修改 JavaScript 对象的状态。

8、napi_define_properties

用于在构造函数初始化时定义一个对象的属性和方法。这个函数允许你一次性定义多个属性,而不是在运行时逐个设置。
napi_define_properties 函数的原型如下:

napi_status napi_define_properties(napi_env env,
                                 napi_value object,
                                 size_t property_count,
                                 const napi_property_descriptor* properties);

参数说明:

  • env:指向当前 NAPI 环境的指针。
  • object:要定义属性的 JavaScript 对象。
  • property_count:要定义的属性数量。
  • properties:指向一个 napi_property_descriptor 数组的指针,该数组描述了要定义的属性。
  • napi_property_descriptor 结构体用于描述每个属性,其原型如下:
typedef struct {
  const char* name;             // 属性或方法的名称
  napi_value getter;             // 获取器函数,如果属性是只读的,则设置为 NULL
  napi_value setter;             // 设置器函数,如果属性是只写的,则设置为 NULL
  napi_value method;            // 方法函数,如果属性不是方法,则设置为 NULL
  napi_value enum_value;        // 枚举值,通常设置为 NULL
  napi_value default_value;      // 默认值,通常设置为 NULL
} napi_property_descriptor;

MyObjectConstructor 函数创建了一个新的 JavaScript 函数 MyObject,并使用 napi_define_properties 定义了它的静态属性 staticProperty 和静态方法 staticMethod。MyObjectMethod 是对象的方法,而 MyStaticMethod 是静态方法。napi_define_properties 函数通常在模块初始化或构造函数中使用,用于定义类原型或对象的属性和方法。

#include <napi.h>
napi_value MyObjectConstructor(napi_env env, napi_callback_info info) {
    // 创建一个新的 JavaScript 对象
    napi_value cons;
    napi_create_function(env, "MyObject", 0, MyObjectMethod, NULL, &cons);

    // 定义属性和方法
    napi_property_descriptor properties[] = {
        {"staticProperty", NULL, NULL, NULL, NULL, NULL},
        {"staticMethod", NULL, NULL, MyStaticMethod, NULL, NULL}
    };
    // 使用 napi_define_properties 定义属性和方法
    napi_status status = napi_define_properties(env, cons, sizeof(properties) / sizeof(properties[0]), properties);
    if (status != napi_ok) {
        // 处理错误
        return nullptr;
    }
    return cons;
}

napi_value MyObjectMethod(napi_env env, napi_callback_info info) {
    // 实现对象的方法
    // ...
    return nullptr;
}

napi_value MyStaticMethod(napi_env env, napi_callback_info info) {
    // 实现静态方法
    // ...
    return nullptr;
}

napi_define_properties 和 napi_set_named_property 都是 Node.js API (NAPI) 中用于操作 JavaScript 对象属性的函数。而napi_define_properties 通常在构造函数或模块初始化时使用,用于定义对象的多个属性和方法。接受一个属性描述符数组,可以一次性定义多个属性。使用 napi_define_properties 定义的属性会成为对象的原型属性,这意味着它们会被对象及其所有实例继承。它是在对象创建时调用的,用于设置对象的初始属性和方法;而napi_set_named_property 用于在运行时动态地设置或修改 JavaScript 对象的单个属性。接受对象、属性名和属性值作为参数;使用 napi_set_named_property 设置的属性是直接属性,它不会成为对象原型的一部分,也不会被对象的实例继承。它可以在任何时候调用,用于更新或添加对象的属性。

9、napi_get_cb_info从napi_callback_info类型的参数中得到回调的参数等数据

用于获取传递给异步回调或定时器回调的附加数据,通常在异步操作的完成回调中使用,以便访问在异步操作开始时附加到回调中的 NAPI 回调信息。napi_get_cb_info 函数的原型如下:

napi_status napi_get_cb_info(napi_env env,
                           napi_callback_info info,
                           size_t* argc,
                           napi_value* argv,
                           napi_value* this_arg,
                           napi_async_context* async_context);

参数说明:

  • env:指向当前 NAPI 环境的指针。
  • info:传递给回调的 napi_callback_info。
  • argc:指向一个 size_t 的指针,用于接收回调中的参数数量。
  • argv:指向一个 napi_value 数组的指针,该数组将被填充回调中的参数。
  • this_arg:指向一个 napi_value 的指针,用于接收回调中的 this 指针。
  • async_context:指向一个 napi_async_context 的指针,用于接收异步操作的上下文信息。
napi_value MyAsyncCallback(napi_env env, napi_callback_info info) {
    // 获取回调信息
    size_t argc;
    napi_value argv[1];
    napi_value this_arg;
    napi_async_context async_context;

    // 使用 napi_get_cb_info 获取回调的参数和上下文
    napi_status status = napi_get_cb_info(env, info, &argc, argv, &this_arg, &async_context);
    if (status != napi_ok) {
        // 处理错误
        return nullptr;
    }

    // 使用 argc, argv, this_arg 和 async_context 进行后续操作
    // ...

    return nullptr;
}

napi_callback_info 中取出 JS 调用时传入的所有参数,并调用 napi 方法将其从 napi 数据类型的值 napi_value 转换成 native 数据类型的值argc为传入参数个数,argv为传入参数数组,此时参数的类型都为napi_value。

10、napi_typeof函数获取入参的实际类型

用于获取给定 napi_value 的类型信息,napi_typeof 函数的原型如下:

napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result);
  • env:指向当前 NAPI 环境的指针。
  • value:要检查类型的 napi_value。
  • result:指向 napi_valuetype 变量的指针,该变量将接收表示 value 类型的枚举值。
    napi_valuetype 枚举包含了多种类型,例如 napi_undefined、napi_null、napi_boolean、napi_number、napi_string、napi_symbol、napi_object、napi_function 等
napi_value CheckValueType(napi_env env, napi_callback_info info) {
    // 假设我们有一个 napi_value 需要检查类型
    napi_value value;
    napi_get_cb_info(env, info, NULL, &value, NULL, NULL);

    // 检查值的类型
    napi_valuetype type;
    napi_typeof(env, value, &type);

    // 根据类型进行不同的操作
    switch (type) {
        case napi_undefined:
            // 处理未定义类型的值
            break;
        case napi_null:
            // 处理空类型的值
            break;
        case napi_number:
            // 处理数字类型的值
            break;
        case napi_string:
            // 处理字符串类型的值
            break;
        // 其他类型的处理...
        default:
            // 未知类型的处理
            break;
    }
    return nullptr;
}

11、napi_get_value_string_utf8方法将napi_string转换char*

napi_status napi_get_value_string_utf8(napi_env env,
  napi_value value,
  char* buf,
  size_t bufsize,
  size_t* result);

12、 napi_module_register

用于注册一个 NAPI 模块。这个函数在模块的初始化代码中被调用,以便将模块的导出函数和属性添加到 Node.js 的全局对象上,从而使得这些函数和属性可以被 JavaScript 代码访问和使用。
napi_module_register 函数的原型如下:

napi_status napi_module_register(napi_env env,
                               napi_object reference,
                               napi_value (*module_init)(napi_env, napi_value),
                               napi_value* result);

参数说明:

  • env:指向当前 NAPI 环境的指针。
  • reference:一个 napi_object,包含了模块的导出对象。这个对象通常是通过调用 napi_create_object 创建的,并且可以包含多个属性和方法。
  • module_init:指向一个函数的指针,该函数用于初始化模块。这个函数将被调用,并且应该返回模块的导出对象。
  • result:指向一个 napi_value 的指针,用于接收注册操作的结果。如果注册成功,这个值将是模块的导出对象。

未完待续…

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

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

相关文章

前端网页打开PC端本地的应用程序实现方案

最近开发有一个需求&#xff0c;网页端有个入口需要跳转三维大屏&#xff0c;而这个大屏是一个exe应用程序。产品需要点击这个入口&#xff0c;并打开这个应用程序。这个就类似于百度网盘网页跳转到PC端应用程序中。 这里我们采用添加自定义协议的方式打开该应用程序。一开始可…

Elasticsearch-RestAPI --学习笔记

RestAPI ES官方提供了各种不同语言的客户端&#xff0c;用来操作ES。这些客户端的本质就是组装DSL语句&#xff0c;通过http请求发送给ES。 官方文档地址&#xff1a; Elasticsearch Clients | Elastic 以下关于RestAPI 的说明都是基于老版本客户端 初始化RestClient 1&…

英语科技写作 希拉里·格拉斯曼-蒂(英文版)pdf下载

下载链接&#xff1a; 链接1&#xff1a;https://pan.baidu.com 链接2&#xff1a;/s/1fxRUGnlJrKEzQVF6k1GmBA 提取码&#xff1a;b69t 由于是英文版&#xff0c;可能有些看着不太方便&#xff0c;可以在网页版使用以下软件中英文对照着看&#xff0c;看着更舒服&#xff0c;…

Docker核心技术:Docker原理之Cgroups

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;Docker原理之Cgroups&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进容器技术要解决哪些问题Docker的基本使用Docker是如何实现的 Docker核心技术&#xff1a;…

扭蛋机潮玩小程序搭建,扭蛋机行业的创新

在当下潮玩市场中&#xff0c;扭蛋机具有盲盒的未知性和惊喜体验感&#xff0c;商品丰富&#xff0c;并且价格相对低廉&#xff0c;获得了极高的人气。年轻人开始对扭蛋机逐渐“上头”&#xff0c;为了扭到喜欢的商品不断地进行复购下单&#xff0c;在这场随机性的扭蛋游戏中&a…

Java语言程序设计——篇七(1)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 继承 类的继承实战演练 方法覆盖实战演练 &#x1f351;super关键字实战演练 调用父类的构造方法 类的继承 通过类的继承方式&#xff0c;可以…

【Qt】QWidget核心属性相关API

目录 一. enabled——是否可用 二. geometry——几何位置 window frame 三. windowTitle——窗口标题 四. windowIcon——窗口图标 ​qrc文件 五. windowOpacity——透明度 六. cursor——光标 自定义光标 七. font——字体 八. toolTip——提示栏 九. focusPolic…

git免密推送代码至仓库gitee/github 常用命令

代码托管 gitee github gitclone 1 生成/添加SSH公钥 ssh-keygen -C "***qq.com"2 gitee添加公钥 查看公钥 cat ~/.ssh/id_rsa.pub然后再gitee添加 3 验证 gitee ssh -T gitgitee.comgithub ssh -T gitgithub.comgitclone&#xff1a;无法测试&#xff0c…

MSSQL注入前置知识

简述 Microsoft SQL server也叫SQL server / MSSQL&#xff0c;由微软推出的关系型数据库&#xff0c;默认端口1433 常见搭配C# / .net IISmssql mssql的数据库文件 数据文件&#xff08;.mdf&#xff09;&#xff1a;主要的数据文件&#xff0c;包含数据表中的数据和对象信息…

Vue3可媲美Element Plus Tree组件开发之append节点

在前面的章节&#xff0c;我们完成了可媲美Element Plus Tree组件的基本开发。通过实现各种计算属性&#xff0c;tree数据状态变化引起的视图更新被计算属性所接管了&#xff0c;无需我们再手动做各种遍历、查找以及手动监听操作&#xff0c;这样后续开发高级功能变得易如反掌啦…

插入和选择排序

1.1直接插入排序 void InsertSort(int* a, int n) {for (int i 1; i < n - 1; i) {//i的范围要注意的&#xff0c;防止指针越界int end i;int tmp a[end 1];while (end>0) {if (tmp< a[end]) {a[end 1] a[end];//小于就挪动&#xff0c;虽然会覆盖后面空间的值…

Qt Creator平台编译snmp++

声明 &#xff1a;本文的大部分资源参考自文章&#xff0c;编译snmp的方法我也是在这里学习的&#xff0c;结合自己的需求&#xff0c;做了snmp和Agent的混合编译。需要了解更多的详情可以点击链接去看原文&#xff0c;我总结了自己的编译过程&#xff0c;并写下此文作为一个回…

Springboot+vue自制可爱英语日记系统-XD动画测试版

目录 项目背景与愿景 项目流程 需求分析 设计之美 技术实现 部署策略 未来展望 项目寄语 项目预览 项目页面展现 引导页(3张) 首页 日记模块 日记模块-写日记 信箱模块 回收箱模块 前端开发 前端开发概述 关键技术选型 开发流程 后端开发 后端开发概述 …

【算法/训练】:动态规划

一、路径类 1. 字母收集 思路&#xff1a; 1、预处理 对输入的字符矩阵我们按照要求将其转换为数字分数&#xff0c;由于只能往下和往右走&#xff0c;因此走到&#xff08;i&#xff0c;j&#xff09;的位置要就是从&#xff08;i - 1&#xff0c; j&#xff09;往下走&#x…

C++笔记3:基类指针delete子类对象的内存泄漏问题

根据《effective C》第7章所述&#xff0c;new的一个子类对象赋值给基类指针delete的时候为了防止子类的析构函数没有调用要在基类的析构函数加上virtual 关键字&#xff1a; #include <stdint.h> #include <iostream> #include <iomanip> #include <vec…

零代码实现GIS视效提升,一键添加体积云体积雾

在三维GIS开发中&#xff0c;场景的真实感和高效性始终是用户的核心需求。为此&#xff0c;山海鲸可视化提供了完美的解决方案。这款免费可视化工具不仅支持多种GIS影像协议&#xff08;TMS、WMS、WMTS等&#xff09;&#xff0c;还可以一键添加体积云和体积雾效果&#xff0c;…

FastGPT 知识库搜索测试功能解析(一)

本文以 FastGPT 知识库的搜索测试功能为入口,分析 FastGPT 的知识检索流程。 一、搜索功能介绍 1.1 整体介绍 搜索测试功能包含三种类型:语义检索、全文检索、混合检索。 语义检索:使用向量进行文本相关性查询,即调用向量数据库根据向量的相似性检索; 全文检索:使用…

Axure软件新功能解析与应用技巧分享

Axure是一种用于创建原型和交互设计的软件工具&#xff0c;广泛应用于操作界面。&#xff08;UI&#xff09;和客户体验&#xff08;UX&#xff09;为了展示和测试应用程序、网站或其他数据产品的性能和操作界面&#xff0c;设计帮助产品经理、设计师和开发者制作具有交互性的原…

17.jdk源码阅读之LinkedBlockingQueue

1. 写在前面 LinkedBlockingQueue 是 Java 并发包中的一个重要类&#xff0c;常用于生产者-消费者模式等多线程编程场景。上篇文章我们介绍了ArrayBlockingQueue&#xff0c;并且与LinkedBlockingQueue做了简单的对比&#xff0c;这篇文章我们来详细分析下LinkedBlockingQueue…

RAS--APEI 报错解析流程(2)

RAS--APEI 报错解析流程(1) 除了APEI 中除了GHES会记录错误&#xff0c;在Post过程中的错误通常是通过BERT Table汇报 1.BERT Boot Error Record Table is used to report unhandled errors that occurred in a previous boot&#xff0c;it is reported as a ‘one-time polle…