Redis:cpp.redis++类型操作
Redis:cpp.redis++类型操作
- string
- set
- mset
- mget
- getrange
- setrange
- incrby
- decrby
- list
- lpush
- rpush
- lrange
- llen
- lpop
- rpop
- blpop
- brpop
- set
- sadd
- smemebers
- sismember
- scard
- spop
- sinter
- sinterstore
- hash
- hset
- hget
- hexists
- hdel
- hkeys
- hvals
- hmset
- hmget
- zset
- zadd
- zrange
- zcard
- zrem
- zscore
- zrank
- 总结
本博客讲解rediis
的C++
客户端redis++
,五大基本类型操作。大部分接口和redis
原生命令没有区别,只是有小部分C++
语法问题。所有接口可以参考文档:[redis-plus-plus/redis.h],本博客只讲解各个类型最核心的接口,以及部分语法注意事项。
本博客讲解接口比较枯燥,接口是看不完的,可以选择直接看总结,那里归纳了redis++
的接口设计规则。
string
set
string
的get
和set
已经在通用接口中讲解过了,但是还有两个默认参数没有说明。
bool set(const StringView &key,const StringView &val,const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),UpdateType type = UpdateType::ALWAYS);
set
的第三个参数用于设置超时时间,第四个参数用于设置NX | XX
选项,有以下三种选项:
ALWAYS
:总是插入新数据,默认值NOT_SXIST
:key
不存在时才插入,存在则什么也不干EXIST
:key
存在时才更新,不存在则什么也不干
示例:
#include <iostream>
#include <chrono>
#include <sw/redis++/redis++.h>int main()
{sw::redis::Redis redis("tcp://127.0.0.1:6379");redis.flushall();redis.set("str1", "111", std::chrono::seconds(5));std::cout << redis.ttl("str1") << std::endl;redis.set("str2", "222", std::chrono::seconds(0), sw::redis::UpdateType::NOT_EXIST);std::cout << redis.get("str2").value() << std::endl;redis.set("str2", "333", std::chrono::seconds(0), sw::redis::UpdateType::NOT_EXIST);std::cout << redis.get("str2").value() << std::endl;return 0;
}
输出结果:
5
222
222
第一次set
测试超时时间,使用ttl
检测超时时间为5s
。第二次用set
测试NOT_EXIST
,由于str2
不存在,插入成功222
。第三次更新str2
为333
,但是设置模式为NOT_EXIST
,由于str2
已经存在,设置失败,str2
依然是222
。
此处想要使用UpdateType
,必须先设置超时时间,如果不想要超时间,就设为0s
。
mset
mset
用于同时设置多个key
,函数原型如下:
template <typename Input>
void mset(Input first, Input last);template <typename T>
void mset(std::initializer_list<T> il);
第一个重载,要输入一个容器迭代器,容器存储的类型是std::pair<std::string, std::string>
,有以下两种用法:
std::vector<std::pair<std::string, std::string>> kvs1 = {{"k1", "v1"}, {"k2", "v2"}};
redis.mset(kvs1.begin(), kvs1.end());
std::unordered_map<std::string, std::string> kvs2 = {{"k3", "v3"}, {"k4", "v4"}};
redis.mset(kvs2.begin(), kvs2.end());
第一种使用std::vector
直接存储std::pair
,此时传入std::vector
的首尾迭代器进行构造。
第二种则是使用C++
库中自带的键值对形式的容器,比如std::map
、std::unordered_map
,传入首尾迭代器进行构造。
而第二个重载,要传入一个初始化列表,列表的每个元素也是std::pair<std::string, std::string>
。
redis.mset({std::make_pair("k1", "v1"), std::make_pair("k2", "v2"), std::make_pair("k3", "v3")});
mget
mset
用于同时获取多个key
,函数原型如下:
template <typename Input, typename Output>
void mget(Input first, Input last, Output output);template <typename T, typename Output>
void mget(std::initializer_list<T> il, Output output) {mget(il.begin(), il.end(), output);
}
mget
也有两种函数重载,第一种把要查询的key
放到input
容器中,然后输入容器的头尾迭代器。还需要一个output
迭代器,用于接收输出的value
。
std::vector<std::string> keys = {"k1", "k2", "k3"};
std::vector<OptionalString> vals;
redis.mget(keys.begin(), keys.end(), std::back_inserter(vals));
同样的,mget
也可以使用初始化列表:
std::vector<OptionalString> vals;
redis.mget({"k1", "k2", "k3"}, std::back_inserter(vals));
getrange
getrange
获取指定范围内的字符,函数声明如下:
std::string getrange(const StringView &key, long long start, long long end);
第一个参数指定要查询的key
,后两个参数分别是起始下标和终止下标,返回一个std::string
,如果为空就返回空字符串,
setrange
setrange
用于从指定下标开始覆盖字符,函数声明如下:
long long setrange(const StringView &key, long long offset, const StringView &val);
第一个参数指定key
,第二个参数为起始下标,从起始下标开始往后的字符串,被val
覆盖。
incrby
incrby
用于给value
增加指定值,函数声明如下:
long long incrby(const StringView &key, long long increment);
第一个参数指定key
,第二个参数为增量,可以为负数。
decrby
long long decrby(const StringView &key, long long decrement);
第一个参数指定key
,第二个参数为减量,可以为负数。
此处有一个要注意的小问题就是,在redis
中int
是使用string
来存储的,但是get
得到的是OptionalString
,此时要自己进行字符串到数字的转化。
list
lpush
lpush
用于插入元素到列表头部,函数声明如下:
long long lpush(const StringView &key, const StringView &val);template <typename Input>
long long lpush(const StringView &key, Input first, Input last);template <typename T>
long long lpush(const StringView &key, std::initializer_list<T> il) {return lpush(key, il.begin(), il.end());
}
第一个函数重载,用于只插入一个元素的情况,第二个重载需要传入一个容器的迭代器,元素类型为std::string
。第三个重载为初始化列表。
容器迭代器版本:
std::vector<std::string> elements = {"e1", "e2", "e3"};
redis.lpush("list", elements.begin(), elements.end());
初始化列表版本:
redis.lpush("list", {"e1", "e2", "e3"});
rpush
rpush
用于插入元素到列表尾部,函数声明如下:
long long rpush(const StringView &key, const StringView &val);template <typename Input>
long long rpush(const StringView &key, Input first, Input last);template <typename T>
long long rpush(const StringView &key, std::initializer_list<T> il) {return rpush(key, il.begin(), il.end());
}
这个用法和lpush
完全一致,只是该函数用于尾插。
lrange
lrange
用于获取list
指定范围内的元素,函数声明如下:
template <typename Output>
void lrange(const StringView &key, long long start, long long stop, Output output);
指定[start, stop]
闭区间,最后将结果通过输出迭代器output
输出到容器中。
示例:
redis.lrange("list", 0, -1, std::back_inserter(elements));
llen
llen
用于获取list
的长度,函数声明如下:
long long llen(const StringView &key);
lpop
lpop
用于获取并删除列表的头部元素,函数声明如下:
OptionalString lpop(const StringView &key);
此处注意返回值是OptionalString
,有可能为空,要进行检查。
示例:
auto element = redis.lpop("list");
if (element)std::cout << *element << std::endl;
elsestd::cout << "list is empty or list does not exist" << std::endl;
rpop
rpop
用于获取并删除列表的尾部元素,函数声明如下:
OptionalString rpop(const StringView &key);
与lpop
用法一致。
blpop
blpop
用于阻塞等待,获取头部元素,函数声明如下:
// 单key版本
OptionalStringPair blpop(const StringView &key, long long timeout);OptionalStringPair blpop(const StringView &key,const std::chrono::seconds &timeout = std::chrono::seconds{0});// 多key,容器迭代器版本
template <typename Input>
OptionalStringPair blpop(Input first, Input last, long long timeout);template <typename Input>
OptionalStringPair blpop(Input first,Input last,const std::chrono::seconds &timeout = std::chrono::seconds{0});// 多key,初始化列表版本
template <typename T>
OptionalStringPair blpop(std::initializer_list<T> il, long long timeout);template <typename T>
OptionalStringPair blpop(std::initializer_list<T> il,const std::chrono::seconds &timeout = std::chrono::seconds{0});
blpop
有六个重载,但是其实这只是同样的功能的不同传参形式而已。对于redis
的阻塞等待,其可以传入一个或者多个key
。前两个函数重载就是对单个key
的特化,它们的key
都是一个StringView
,timeout
用于设置超时时间,而超时时间又可以分为long long
类型和std::chrono
类型,所以有两个重载。
对于多个key
的情况,为了传入多个key
,第三个和第四个重载使用了容器迭代器的传参方式,容器元素为key
。而第五个和第六个重载,使用了初始化列表的传参方式。
而blpop
的返回值,是一个OptionalStringPair
,第一个成员是key
,表示该数据是从哪一个list
得到的,第二个成员OptionalStringPair.value().second
才是获取到的值。
另外的,OptionalStringPair
有两种方式可访问成员,第一种是通过value()
方法获取std::pair
:
OptionalStringPair.value().first;
OptionalStringPair.value().second;
另一种是通过->
直接访问:
OptionalStringPair->first;
OptionalStringPair->second;
由于该函数也有可能返回空,所以也是Optional
系列,使用之前要检测是否为空。
示例:
std::vector<std::string> keys = {"k1", "k2", "k3"};
auto ret = redis.blpop(keys.begin(), keys.end(), 10);
if (ret)std::cout << ret->first << " : " << ret->second << std::endl;
brpop
brpop
用于阻塞等待,获取尾部元素,函数声明如下:
// 单key版本
OptionalStringPair brpop(const StringView &key, long long timeout);OptionalStringPair brpop(const StringView &key,const std::chrono::seconds &timeout = std::chrono::seconds{0});// 多key,容器迭代器版本
template <typename Input>
OptionalStringPair brpop(Input first, Input last, long long timeout);template <typename Input>
OptionalStringPair brpop(Input first,Input last,const std::chrono::seconds &timeout = std::chrono::seconds{0});// 多key,初始化列表版本
template <typename T>
OptionalStringPair brpop(std::initializer_list<T> il, long long timeout);template <typename T>
OptionalStringPair brpop(std::initializer_list<T> il,const std::chrono::seconds &timeout = std::chrono::seconds{0});
这个用法和blpop
完全一致。
set
sadd
sadd
用于往set
中插入元素,或者创建一个set
,函数声明如下:
long long sadd(const StringView &key, const StringView &member);template <typename Input>
long long sadd(const StringView &key, Input first, Input last);template <typename T>
long long sadd(const StringView &key, std::initializer_list<T> il);
三种初始化方法,分别是一次只添加一个元素、使用容器迭代器、使用初始化列表。
示例:
redis.sadd("set1", "value1");std::set<std::string> values;
redis.sadd("set2", values.begin(), values.end());
redis.sadd("set3", {"value1", "value2"});
smemebers
smembers
用于获取set
中的所有元素,函数声明如下:
template <typename Output>
void smembers(const StringView &key, Output output);
示例:
std::unordered_set<std::string> members1;
redis.smembers("set", std::inserter(members1, members1.begin()));
std::vector<std::string> members2;
redis.smembers("set", std::back_inserter(members2));
此处要注意,std::set
或者std::unordered_set
的插入迭代器,必须使用inserter
,因为其没有提供头尾插入的接口。
sismember
sismember
用于检测一个数据是否在set
中,函数声明如下:
bool sismember(const StringView &key, const StringView &member);
scard
scard
用于获取元素的个数,函数声明如下:
long long scard(const StringView &key);
spop
spop
用于获取set
中的一个随机元素,函数声明如下:
OptionalString spop(const StringView &key);template <typename Output>
void spop(const StringView &key, long long count, Output output);
示例:
std::vector<std::string> members;
redis.spop("set", 10, std::back_inserter(members));
sinter
sinter
用于求集合的交集,函数声明如下:
template <typename Input, typename Output>
void sinter(Input first, Input last, Output output);template <typename T, typename Output>
void sinter(std::initializer_list<T> il, Output output);
第一个重载输入容器迭代器,第二个重载输入初始化列表,这里面放的是要进行求交集的多个set
。
最后将结果输出到插入迭代器output
中。
示例:
std::set<std::string> results;
auto it = std::inserter(result, resulter.end());
redis.sinter({"set1", "set2"}, it);
sinterstore
sinterstore
用于求出集合的交集,并放到其他集合中,函数声明如下:
long long sinterstore(const StringView &destination, const StringView &key);template <typename Input>
long long sinterstore(const StringView &destination,Input first,Input last);template <typename T>
long long sinterstore(const StringView &destination,std::initializer_list<T> il);
三个重载的第一个参数都是destination
,求出的交集会被存放到这个set
中。第一个重载是对单个set
的特化,后续两个重载分别输入一个迭代器或者初始化列表,内部放要求交集的多个set
。
hash
hset
hset
用于向哈希表插入元素,或者创建一个哈希,函数声明如下:
long long hset(const StringView &key, const StringView &field, const StringView &val);long long hset(const StringView &key, const std::pair<StringView, StringView> &item);template <typename Input>
auto hset(const StringView &key, Input first, Input last)-> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type;template <typename T>
long long hset(const StringView &key, std::initializer_list<T> il);
hset
有 四个重载,前两个重载用于插入单个键值对,后两个重载用于插入多个键值对。
hget
hget
用于获取hash
中指定的field
的值,函数声明如下:
OptionalString hget(const StringView &key, const StringView &field);
hexists
hexists
用于检测field
是否存在,函数声明如下:
bool hexists(const StringView &key, const StringView &field);
hdel
hdel
用于删除指定的field
,函数声明如下:
long long hdel(const StringView &key, const StringView &field);template <typename Input>
long long hdel(const StringView &key, Input first, Input last);template <typename T>
long long hdel(const StringView &key, std::initializer_list<T> il);
该接口支持同时删除多个field
。
示例:
redis.hdel("hash1", "field1");
redis,hdel("hash1", {"field2", "field3"});
hkeys
hkeys
用于获取hash
中所有的field
,函数声明如下:
template <typename Output>
void hkeys(const StringView &key, Output output);
hkeys
要使用插入迭代器获取返回值。
示例:
std::vector<std::string> fields;
auto it = std::back_inserter(fields);
redis.hekys("hash1", it);
hvals
hvals
用于获取hash
中所有的value
,函数声明如下:
template <typename Output>
void hvals(const StringView &key, Output output);
用法同hvals
。
hmset
hmset
用于设置多对field - value
,函数声明如下:
template <typename Input>
void hmset(const StringView &key, Input first, Input last);template <typename T>
void hmset(const StringView &key, std::initializer_list<T> il);
分别是使用容器迭代器和初始化列表,其中容器的成员为std::pair
。
示例:
// 容器迭代器版本
std::unordered_map<std::string, std::string> m = {{"f1", "v1"}, {"f2", "v2"}};
redis.hmset("hash", m.begin(), m.end());
// 初始化列表版本
redis.hmset("hash", {std::make_pair("f1", "v1"), std::make_pair("f2", "v2")});
hmget
hmget
用于同时获取多个field - value
键值对,函数声明如下:
template <typename Input, typename Output>
void hmget(const StringView &key, Input first, Input last, Output output);template <typename T, typename Output>
void hmget(const StringView &key, std::initializer_list<T> il, Output output);
其中初始化列表,和容器迭代器用于输入多个fields
,返回对应的value
,通过插入迭代器输出到接收容器。
示例:
std::vector<OptionalString> vals;
redis.hmget("hash", {"f1", "f2"}, std::back_inserter(vals));
zset
zadd
zadd
用于往zset
中插入元素,函数声明如下:
long long zadd(const StringView &key,const StringView &member,double score,UpdateType type = UpdateType::ALWAYS,bool changed = false);template <typename Input>
long long zadd(const StringView &key,Input first,Input last,UpdateType type = UpdateType::ALWAYS,bool changed = false);template <typename T>
long long zadd(const StringView &key,std::initializer_list<T> il,UpdateType type = UpdateType::ALWAYS,bool changed = false);
第一个重载是插入单个元素的特化,后两个重载支持同时插入多个元素。插入多个元素时,可以通过容器迭代器或初始化列表。最后函数返回插入的元素个数。
最后两个参数在先前已经讲解过。
示例:
reids,zadd("zset1", {std::make_pair("lisa", 60.5), std::make_pair("bob", 20.5)});
zrange
zrange
用于查询zset
中指定范围的元素,函数声明如下:
template <typename Output>
void zrange(const StringView &key, long long start, long long stop, Output output);
这种范围查询,都有withscore
选项,用于获取score
,但是这个zrange
只有一个重载,如何设置withoutscore
?
此处在zrange
内部,会判断插入迭代器output
指向的容器元素类型,如果容器元素是std::string
,那么只返回field
,如果是std::pair<std::string, double>
,那么就会带着score
一起返回。
示例:
// send *ZRANGE* command without the *WITHSCORES* option:
std::vector<std::string> result;
redis.zrange("zset", 0, -1, std::back_inserter(result));
// send command with *WITHSCORES* option:
std::vector<std::pair<std::string, double>> with_score;
redis.zrange("zset", 0, -1, std::back_inserter(with_score));
zcard
zcard
用于获取zset
中的元素个数,函数声明如下:
long long zcard(const StringView &key);
zrem
zrem
用于删除zset
的元素,函数声明如下:
long long zrem(const StringView &key, const StringView &member);template <typename Input>
long long zrem(const StringView &key, Input first, Input last);template <typename T>
long long zrem(const StringView &key, std::initializer_list<T> il)
同理,对于删除单个元素情况,直接传入member
,当要删除多个时,将member
放到容器中或者初始化列表。
zscore
zscore
用于获取member
的score
,函数声明如下:
OptionalDouble zscore(const StringView &key, const StringView &member);
zrank
zrank
用于获取member
的排名,函数声明如下:
OptionalLongLong zrank(const StringView &key, const StringView &member);
总结
其实你会发现,redis++
的接口用法和redis
原生的几乎没有区别。
在需要输入多个参数时,有两种方法:
- 使用容器保存参数,输入容器的迭代器
- 使用初始化列表直接传参
如果要传入键值对,那么就使用std::pair
来维护键值关系。
另外的,常用的C++
类型如下:
OptionalString
:接收value
返回值,可以判断是否为nil
StringView
:key
、field
传参时使用的类型,只读字符串,不能对字符串进行增删操作,其实直接传std::string
就行long long
:只要返回值是整数,几乎都用long long
接收double
:zset
中score
使用的类型
如果函数要输出多个变量,此时就要传入插入迭代器,这个在[Redis:cpp.redis++通用接口]讲解过。
相关文章:

Redis:cpp.redis++类型操作
Redis:cpp.redis类型操作 stringsetmsetmgetgetrangesetrangeincrbydecrby listlpushrpushlrangellenlpoprpopblpopbrpop setsaddsmemeberssismemberscardspopsintersinterstore hashhsethgethexistshdelhkeyshvalshmsethmget zsetzaddzrangezcardzremzscorezrank 总…...

感冒用药记录
问题描述:国庆感冒了,头昏喉咙不舒服 用药过程: – 前3天:未用药,不好也不坏 – 中间2天:开始喉痛,使用复方氨酚烷胺胶囊【含对乙酰氨基酚】,基本没有效果 – 后面1天:开…...

JMeter性能测试时,如何做CSV参数化
在现代软件开发中,性能测试是保证应用程序在高负载条件下稳定运行的重要环节。为了实现真实场景的测试,参数化技术应运而生。其中,CSV参数化是一种高效且灵活的方法,可以让测试人员通过外部数据文件驱动测试脚本,从而模…...

爬虫获取不同数据类型(如JSON,HTML)的处理方法以及图片相对URL地址的转换
当我们爬取图片的URL地址时,我们要确保它们都是有效的绝对URL,这样就可以直接用这些URL来下载图片了。但是很多时候,它们都不是绝对URL地址,因此我们需要它进行URL转换。 if img_url.startswith(//): 这个条件检查URL是否以//开头…...

Elasticsearch 实战应用
Elasticsearch 实战应用 引言 Elasticsearch 是一个分布式、RESTful 风格的搜索和分析引擎,能够快速、实时地处理大规模数据,广泛应用于全文搜索、日志分析、推荐系统等领域。在这篇博客中,我们将从 Elasticsearch 的基本概念入手ÿ…...

前端数据加载慢的解决方法
都是和前端性能优化非常类似的做法。 1. 懒加载 (Lazy Loading) 对于图片、视频等资源,或者某些组件,在用户滚动到相关区域时再加载,而不是页面一开始就加载所有内容。使用 IntersectionObserver 实现懒加载,或者一些 UI 框架&am…...

探索MultiApp:一款强大的多应用管理工具
探索MultiApp:一款强大的多应用管理工具 在这个数字化时代,多任务并行已经成为我们日常生活的一部分。无论是工作还是娱乐,我们都需要频繁地在多个应用之间切换。今天,我要向大家介绍一款能够帮助你在同一设备上无缝切换和管理多…...

qt QGraphicsItem详解
一、概述 QGraphicsItem是Qt框架中图形视图框架(Graphics View Framework)的一个核心组件,它是用于表示2D图形元素的基类。 它支持的功能包括: 设置和获取图形项的位置和尺寸。控制图形项的外观,如颜色、笔刷、边框…...

LVS搭建负载均衡
LVS搭建负载均衡 引言 在现代互联网应用中,用户对服务的可用性和响应速度要求越来越高。为了应对高并发请求,保证系统的稳定性和容错能力,负载均衡技术应运而生。LVS(Linux Virtual Server)是一种高性能、高可用性的…...

Unity MVC框架演示 1-1 理论分析
本文仅作学习笔记分享与交流,不做任何商业用途,该课程资源来源于唐老狮 1.一般的图解MVC 什么是MVC我就不说了,老生常谈,网上有大量的介绍,想看看这三层都起到什么职责?那就直接上图吧 2.我举一个栗子 我有…...

基于springboot+vue人脸识别的考勤管理系统(源码+定制+开发)
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...

【api连接ChatGPT的最简单方式】
通过api连接ChatGPT的最简单方式 建立client 其中base_url为代理,若连接官网可省略;配置环境变量 from openai import OpenAI client OpenAI(base_url"https://api.chatanywhere.tech/v1" )或给出api和base_url client OpenAI(api_key&…...

技术成神之路:设计模式(二十)装饰模式
介绍 装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象自身的情况下,动态地为对象添加额外的职责。这个模式通常用于增强或改变对象的功能。 1.定义 装饰模式通过创建一个装饰类,将功能动态地添加…...

利用特征点采样一致性改进icp算法点云配准方法
1、index、vector 2、kdtree和kdtreeflann 3、if kdtree.radiusSearch(。。。) > 0)...

LabVIEW惯性导航系统仿真平台
LabVIEW开发捷联惯性导航系统仿真平台,采用模块化设计,利用LabVIEW的图形化编程特性,提高了系统仿真的效率和精度,同时具备良好的可扩展性和用户交互性。 项目背景 当前,惯性导航系统(INS)的研…...

es简单实现文章检索功能
使用的api是:Elasticsearch Java API client 8.0 官网:Package structure and namespace clients | Elasticsearch Java API Client [8.15] | Elastic 1.建立索引库 实现搜索功能字段: title:文章标题content:文章内…...

太速科技-607-基于FMC的12收和12发的光纤子卡
基于FMC的12收和12发的光纤子卡 一、板卡概述 本卡是一个FPGA夹层卡(FMC)模块,可提供高达2个CXP模块接口,提供12路收,12路发的光纤通道。每个通道支持10Gbps,通过Aurora协议,可以组成X4࿰…...

UEFI学习笔记(十):系统表与ACPI表的遍历
一、概述 在 UEFI 系统表中,有几个关键的表用于提供系统信息、服务和硬件抽象。这些表可以通过 EFI_SYSTEM_TABLE 访问,常见的 UEFI 系统表如下: 1、EFI_SYSTEM_TABLE (系统表) EFI_SYSTEM_TABLE 是一个指针,包含多个服务和系统…...

【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。
【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。 【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。 文章目录 【深度学习基础模型】液态状态机࿰…...

深入理解链表(SList)操作
目录: 一、 链表介绍1.1、 为什么引入链表1.2、 链表的概念及结构1.3、 链表的分类 二、 无头单向非[循环链表](https://so.csdn.net/so/search?q循环链表&spm1001.2101.3001.7020)的实现2.1、 [单链表](https://so.csdn.net/so/search?q单链表&spm1001.2…...

03. prometheus 监控 Linux 主机
文章目录 一、prometheus 监控 Linux 主机二、防火墙打开端口1. 方式一:使用 iptables 添加白名单(推荐使用):2. 方式二:重载防火墙 一、prometheus 监控 Linux 主机 1. 官网下载 node_exporter 官网:htt…...

AI占据2024诺贝尔两大奖项,是否预示着未来AI即一切?
本次诺贝尔物理学和学奖的获得者都与AI息息相关,可谓是“AI领域的大丰收”。 2024年诺贝尔物理学奖揭晓:瑞典皇家科学院公布了2024年诺贝尔物理学奖的获得者。他们是美国的约翰霍普菲尔德(John J. Hopfield),以及加拿…...

[已解决] Install PyTorch 报错 —— OpenOccupancy 配环境
目录 关于 常见的初始化报错 环境推荐 torch, torchvision & torchaudio cudatoolkit 本地pip安装方法 关于 OpenOccupancy: 语义占用感知对于自动驾驶至关重要,因为自动驾驶汽车需要对3D城市结构进行细粒度感知。然而,现有的相关基准在城市场…...

6. PH47 代码框架硬件开发环境搭建
概述 PH47代码框架的硬件开发环境搭建同样简单, 建立基本的 PH47 框架学习或二次开发的硬件开发环境所需设备如下: BBP 飞控板及相关软硬件: BBP飞控板,或者至少一块Stm32F411核心板(WeAct Studio)Stm32程序烧录工具…...

package.json配置
package.json配置 描述配置文件配置脚本配置依赖配置发布配置系统配置第三方配置 描述配置 name : 项目名称,第三方包可以通过npm install 包名安装 "name":"react"version : 项目版本,项目版本号 "version" : "18.2…...

视频怎么转gif动图?5个简单转换方法快来学(详细教程)
相信大家在社交平台上会经常看到一些有趣的gif动图表情包,有些小伙伴就会问:这些GIF动图是如何制作的呢?一般GIF动图表情包可以用视频来制作,今天小编就来给大家分享几个视频转成GIF动图的方法,相信通过以下的几个方法…...

10月更新:优维EasyOps®需求解决更彻底,功能体验再升级
升 级 不 止 步 欢迎来到 需求至上,功能完善 的 \ EasyOps 7.5版本 / 👇 >> 联动架构视图:深度融合监控与资源拓扑 传统上,依赖监控态势感知系统固有的分层拓扑结构虽有其优势,但在处理复杂系统尤其是核心数…...

黑马javaWeb笔记重点备份1:三层架构、IOC、DI
来自:【黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖SpringMyBatisSpringMVCSpringBoot等)】 https://www.bilibili.com/video/BV1m84y1w7Tb/?p75&share_sourcecopy_web&vd_source9332b8fc5ea8d349a54c398…...

大坝渗流监测设备——渗压计
渗压计是一种用于监测大坝等水工建筑物渗流压力的重要设备,其准确性和可靠性对于保障大坝安全运行至关重要。南京峟思将为大家详细介绍渗压计的工作原理、安装方法及其在大坝渗流监测中的应用。 渗压计主要利用振弦频率的变化来测量渗透水压力。设备由透水部件、感应…...

Pikachu-Sql Inject-宽字节注入
基本概念 宽字节是相对于ascII这样单字节而言的;像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等这些都是常说的宽字节,实际上只有两字节 GBK 是一种多字符的编码,通常来说,一个 gbk 编码汉字,占用2个字节。一个…...