深圳手机网站建设/搜索软件

深圳手机网站建设,搜索软件,开发建设信息的网站,备案主体负责人和网站负责人Redis 在项目开发中redis的使用也比较频繁,本文介绍了Go语言中go-redis库的基本使用。 Redis介绍 Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外&am…

Redis

在项目开发中redis的使用也比较频繁,本文介绍了Go语言中go-redis库的基本使用。

Redis介绍

Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外,通过复制、持久化和客户端分片等特性,我们可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。

Redis支持的数据结构

Redis支持诸如字符串(string)、哈希(hashe)、列表(list)、集合(set)、带范围查询的排序集合(sorted set)、bitmap、hyperloglog、带半径查询的地理空间索引(geospatial index)和流(stream)等数据结构。

Redis应用场景

  • 缓存系统,减轻主数据库(MySQL)的压力。
  • 计数场景,比如微博、抖音中的关注数和粉丝数。
  • 热门排行榜,需要排序的场景特别适合使用ZSET。
  • 利用 LIST 可以实现队列的功能。
  • 利用 HyperLogLog 统计UV、PV等数据。
  • 使用 geospatial index 进行地理位置相关查询。

准备Redis环境

读者可以选择在本机安装 redis 或使用云数据库,这里直接使用Docker启动一个 redis 环境,方便学习使用。

使用下面的命令启动一个名为 redis507 的 5.0.7 版本的 redis server环境。

docker run --name redis507 -p 6379:6379 -d redis:5.0.7

注意: 此处的版本、容器名和端口号可以根据自己需要设置。

启动一个 redis-cli 连接上面的 redis server。

docker run -it --network host --rm redis:5.0.7 redis-cli

go-redis库

安装

Go 社区中目前有很多成熟的 redis client 库,比如GitHub - gomodule/redigo: Go client for Redis 和GitHub - redis/go-redis: Redis Go client,读者可以自行选择适合自己的库。本文使用 go-redis 这个库来操作 Redis 数据库。

使用以下命令下安装 go-redis 库。

安装v8版本:

go get github.com/redis/go-redis/v8

安装v9版本:

go get github.com/redis/go-redis/v9

连接

在项目中导入 go-redis库(请根据实际情况导入自己需要的版本)。

import "github.com/redis/go-redis/v9"

SetNX方法仅在键不存在时设置值:

err := rdb.SetNX(ctx, "key1", "value", 0).Err()
if err != nil {panic(err)
}

2.5.1 添加和删除
ZAdd用于添加或更新元素,ZRem用于删除元素:

err := rdb.ZAdd(ctx, "key", &redis.Z{Score: 2.5, Member: "zhangsan"}).Err()
if err != nil {
    panic(err)
}

rdb.ZRem(ctx, "key", "zhangsan")

2.5.2 查询操作
ZRange和ZRevRange用于按分数排序返回元素,ZScore用于查询元素的分数:

vals, err := rdb.ZRange(ctx, "key", 0, -1).Result()
if err != nil {
    panic(err)
}
fmt.Println(vals)

score, err := rdb.ZScore(ctx, "key", "zhangsan").Result()
if err != nil {
    panic(err)
}
fmt.Println(score)

                        
原文链接:https://blog.csdn.net/weixin_73833086/article/details/146127620

普通连接模式

注意 如果 redis 的值不存的情况下:

if err == redis.Nil   的情况判断

go-redis 库中使用 redis.NewClient 函数连接 Redis 服务器。

rdb := redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // 密码DB:       0,  // 数据库PoolSize: 20, // 连接池大小
})

除此之外,还可以使用 redis.ParseURL 函数从表示数据源的字符串中解析得到 Redis 服务器的配置信息。

opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")
if err != nil {panic(err)
}rdb := redis.NewClient(opt)
TLS连接模式

如果使用的是 TLS 连接方式,则需要使用 tls.Config 配置。

rdb := redis.NewClient(&redis.Options{TLSConfig: &tls.Config{MinVersion: tls.VersionTLS12,// Certificates: []tls.Certificate{cert},// ServerName: "your.domain.com",},
})
Redis Sentinel模式  哨兵模式

使用下面的命令连接到由 Redis Sentinel 管理的 Redis 服务器。

rdb := redis.NewFailoverClient(&redis.FailoverOptions{MasterName:    "master-name",SentinelAddrs: []string{":9126", ":9127", ":9128"},
})
Redis Cluster模式 集群模式

使用下面的命令连接到 Redis Cluster,go-redis 支持按延迟或随机路由命令。

rdb := redis.NewClusterClient(&redis.ClusterOptions{Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},// 若要根据延迟或随机路由命令,请启用以下命令之一// RouteByLatency: true,// RouteRandomly: true,
})

基本使用

执行命令

下面的示例代码演示了 go-redis 库的基本使用。

// doCommand go-redis基本使用示例
func doCommand() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()// 执行命令获取结果val, err := rdb.Get(ctx, "key").Result()fmt.Println(val, err)// 先获取到命令对象cmder := rdb.Get(ctx, "key")fmt.Println(cmder.Val()) // 获取值fmt.Println(cmder.Err()) // 获取错误// 直接执行命令获取错误err = rdb.Set(ctx, "key", 10, time.Hour).Err()// 直接执行命令获取值value := rdb.Get(ctx, "key").Val()fmt.Println(value)
}

执行任意命令

go-redis 还提供了一个执行任意命令或自定义命令的 Do 方法,特别是一些 go-redis 库暂时不支持的命令都可以使用该方法执行。具体使用方法如下。

// doDemo rdb.Do 方法使用示例
func doDemo() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()// 直接执行命令获取错误err := rdb.Do(ctx, "set", "key", 10, "EX", 3600).Err()fmt.Println(err)// 执行命令获取结果val, err := rdb.Do(ctx, "get", "key").Result()fmt.Println(val, err)
}

redis.Nil

go-redis 库提供了一个 redis.Nil 错误来表示 Key 不存在的错误。因此在使用 go-redis 时需要注意对返回错误的判断。在某些场景下我们应该区别处理 redis.Nil 和其他不为 nil 的错误。

// getValueFromRedis redis.Nil判断
func getValueFromRedis(key, defaultValue string) (string, error) {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()val, err := rdb.Get(ctx, key).Result()if err != nil {// 如果返回的错误是key不存在if errors.Is(err, redis.Nil) {return defaultValue, nil}// 出其他错了return "", err}return val, nil
}

其他示例

zset示例

下面的示例代码演示了如何使用 go-redis 库操作 zset。

// zsetDemo 操作zset示例
func zsetDemo() {// keyzsetKey := "language_rank"// value// 注意:v8版本使用[]*redis.Z;此处为v9版本使用[]redis.Zlanguages := []redis.Z{{Score: 90.0, Member: "Golang"},{Score: 98.0, Member: "Java"},{Score: 95.0, Member: "Python"},{Score: 97.0, Member: "JavaScript"},{Score: 99.0, Member: "C/C++"},}ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()// ZADDerr := rdb.ZAdd(ctx, zsetKey, languages...).Err()if err != nil {fmt.Printf("zadd failed, err:%v\n", err)return}fmt.Println("zadd success")// 把Golang的分数加10newScore, err := rdb.ZIncrBy(ctx, zsetKey, 10.0, "Golang").Result()if err != nil {fmt.Printf("zincrby failed, err:%v\n", err)return}fmt.Printf("Golang's score is %f now.\n", newScore)// 取分数最高的3个ret := rdb.ZRevRangeWithScores(ctx, zsetKey, 0, 2).Val()for _, z := range ret {fmt.Println(z.Member, z.Score)}// 取95~100分的op := &redis.ZRangeBy{Min: "95",Max: "100",}ret, err = rdb.ZRangeByScoreWithScores(ctx, zsetKey, op).Result()if err != nil {fmt.Printf("zrangebyscore failed, err:%v\n", err)return}for _, z := range ret {fmt.Println(z.Member, z.Score)}
}

执行上面的函数将得到如下输出结果。

zadd success
Golang's score is 100.000000 now.
Golang 100
C/C++ 99
Java 98
Python 95
JavaScript 97
Java 98
C/C++ 99
Golang 100

扫描或遍历所有key

在Redis中可以使用KEYS prefix* 命令按前缀查询所有符合条件的 key,go-redis库中提供了Keys方法实现类似查询key的功能。

例如使用以下命令查询以user:为前缀的所有key(user:cart:00user:order:2023等)。

vals, err := rdb.Keys(ctx, "user:*").Result()

但是如果需要扫描数百万的 key ,那速度就会比较慢。这种场景下你可以使用Scan命令来遍历所有符合要求的 key。

// scanKeysDemo1 按前缀查找所有key示例
func scanKeysDemo1() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()var cursor uint64for {var keys []stringvar err error// 将redis中所有以prefix:为前缀的key都扫描出来keys, cursor, err = rdb.Scan(ctx, cursor, "prefix:*", 0).Result()if err != nil {panic(err)}for _, key := range keys {fmt.Println("key", key)}if cursor == 0 { // no more keysbreak}}
}

针对这种需要遍历大量key的场景,go-redis中提供了一个简化方法——Iterator,其使用示例如下。

// scanKeysDemo2 按前缀扫描key示例
func scanKeysDemo2() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()// 按前缀扫描keyiter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator()for iter.Next(ctx) {fmt.Println("keys", iter.Val())}if err := iter.Err(); err != nil {panic(err)}
}

例如,我们可以写出一个将所有匹配指定模式的 key 删除的示例。

// delKeysByMatch 按match格式扫描所有key并删除
func delKeysByMatch(match string, timeout time.Duration) {ctx, cancel := context.WithTimeout(context.Background(), timeout)defer cancel()iter := rdb.Scan(ctx, 0, match, 0).Iterator()for iter.Next(ctx) {err := rdb.Del(ctx, iter.Val()).Err()if err != nil {panic(err)}}if err := iter.Err(); err != nil {panic(err)}
}

此外,对于 Redis 中的 set、hash、zset 数据类型,go-redis 也支持类似的遍历方法。

iter := rdb.SScan(ctx, "set-key", 0, "prefix:*", 0).Iterator()
iter := rdb.HScan(ctx, "hash-key", 0, "prefix:*", 0).Iterator()
iter := rdb.ZScan(ctx, "sorted-hash-key", 0, "prefix:*", 0).Iterator(

Pipeline

Redis Pipeline 允许通过使用单个 client-server-client 往返执行多个命令来提高性能。区别于一个接一个地执行100个命令,你可以将这些命令放入 pipeline 中,然后使用1次读写操作像执行单个命令一样执行它们。这样做的好处是节省了执行命令的网络往返时间(RTT)。

y在下面的示例代码中演示了使用 pipeline 通过一个 write + read 操作来执行多个命令。

pipe := rdb.Pipeline()incr := pipe.Incr(ctx, "pipeline_counter")
pipe.Expire(ctx, "pipeline_counter", time.Hour)cmds, err := pipe.Exec(ctx)
if err != nil {panic(err)
}// 在执行pipe.Exec之后才能获取到结果
fmt.Println(incr.Val())

上面的代码相当于将以下两个命令一次发给 Redis Server 端执行,与不使用 Pipeline 相比能减少一次RTT。

INCR pipeline_counter
EXPIRE pipeline_counts 3600

或者,你也可以使用Pipelined 方法,它会在函数退出时调用 Exec。

var incr *redis.IntCmdcmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {incr = pipe.Incr(ctx, "pipelined_counter")pipe.Expire(ctx, "pipelined_counter", time.Hour)return nil
})
if err != nil {panic(err)
}// 在pipeline执行后获取到结果
fmt.Println(incr.Val())

我们可以遍历 pipeline 命令的返回值依次获取每个命令的结果。下方的示例代码中使用pipiline一次执行了100个 Get 命令,在pipeline 执行后遍历取出100个命令的执行结果。

cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {for i := 0; i < 100; i++ {pipe.Get(ctx, fmt.Sprintf("key%d", i))}return nil
})
if err != nil {panic(err)
}for _, cmd := range cmds {fmt.Println(cmd.(*redis.StringCmd).Val())
}

在那些我们需要一次性执行多个命令的场景下,就可以考虑使用 pipeline 来优化。

事务

Redis 是单线程执行命令的,因此单个命令始终是原子的,但是来自不同客户端的两个给定命令可以依次执行,例如在它们之间交替执行。但是,Multi/exec能够确保在multi/exec两个语句之间的命令之间没有其他客户端正在执行命令。

在这种场景我们需要使用 TxPipeline 或 TxPipelined 方法将 pipeline 命令使用 MULTI 和EXEC包裹起来。

// TxPipeline demo
pipe := rdb.TxPipeline()
incr := pipe.Incr(ctx, "tx_pipeline_counter")
pipe.Expire(ctx, "tx_pipeline_counter", time.Hour)
_, err := pipe.Exec(ctx)
fmt.Println(incr.Val(), err)// TxPipelined demo
var incr2 *redis.IntCmd
_, err = rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {incr2 = pipe.Incr(ctx, "tx_pipeline_counter")pipe.Expire(ctx, "tx_pipeline_counter", time.Hour)return nil
})
fmt.Println(incr2.Val(), err)

上面代码相当于在一个RTT下执行了下面的redis命令:

MULTI
INCR pipeline_counter
EXPIRE pipeline_counts 3600
EXEC

Watch

我们通常搭配 WATCH命令来执行事务操作。从使用WATCH命令监视某个 key 开始,直到执行EXEC命令的这段时间里,如果有其他用户抢先对被监视的 key 进行了替换、更新、删除等操作,那么当用户尝试执行EXEC的时候,事务将失败并返回一个错误,用户可以根据这个错误选择重试事务或者放弃事务。

Watch方法接收一个函数和一个或多个key作为参数。

Watch(fn func(*Tx) error, keys ...string) error

下面的代码片段演示了 Watch 方法搭配 TxPipelined 的使用示例。

// watchDemo 在key值不变的情况下将其值+1
func watchDemo(ctx context.Context, key string) error {return rdb.Watch(ctx, func(tx *redis.Tx) error {n, err := tx.Get(ctx, key).Int()if err != nil && err != redis.Nil {return err}// 假设操作耗时5秒// 5秒内我们通过其他的客户端修改key,当前事务就会失败time.Sleep(5 * time.Second)_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {pipe.Set(ctx, key, n+1, time.Hour)return nil})return err}, key)
}

将上面的函数执行并打印其返回值,如果我们在程序运行后的5秒内修改了被 watch 的 key 的值,那么该事务操作失败,返回redis: transaction failed错误。

最后我们来看一个 go-redis 官方文档中使用 GET 、SETWATCH命令实现一个 INCR 命令的完整示例。

// 此处rdb为初始化的redis连接客户端
const routineCount = 100// 设置5秒超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()// increment 是一个自定义对key进行递增(+1)的函数
// 使用 GET + SET + WATCH 实现,类似 INCR
increment := func(key string) error {txf := func(tx *redis.Tx) error {// 获得当前值或零值n, err := tx.Get(ctx, key).Int()if err != nil && err != redis.Nil {return err}// 实际操作(乐观锁定中的本地操作)n++// 仅在监视的Key保持不变的情况下运行_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {// pipe 处理错误情况pipe.Set(ctx, key, n, 0)return nil})return err}// 最多重试100次for retries := routineCount; retries > 0; retries-- {err := rdb.Watch(ctx, txf, key)if err != redis.TxFailedErr {return err}// 乐观锁丢失}return errors.New("increment reached maximum number of retries")
}// 开启100个goroutine并发调用increment
// 相当于对key执行100次递增
var wg sync.WaitGroup
wg.Add(routineCount)
for i := 0; i < routineCount; i++ {go func() {defer wg.Done()if err := increment("counter3"); err != nil {fmt.Println("increment error:", err)}}()
}
wg.Wait()n, err := rdb.Get(ctx, "counter3").Int()
fmt.Println("最终结果:", n, err)

copy

在这个示例中使用了 redis.TxFailedErr 来检查事务是否失败。

更多详情请查阅官方文档。

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

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

相关文章

fastapi+angular外卖系统

说明&#xff1a; fastapiangular外卖系统 1.美食分类&#xff08;粥&#xff0c;粉&#xff0c;面&#xff0c;炸鸡&#xff0c;炒菜&#xff0c;西餐&#xff0c;奶茶等等&#xff09; 2.商家列表 &#xff08;kfc&#xff0c;兰州拉面&#xff0c;湘菜馆&#xff0c;早餐店…

NFS共享搭建

准备工作 首先确保已经建了两台虚拟机&#xff0c;都是桥接模式&#xff0c;一台是windows server 2019 一台是centos7 用户配额教程,是在windows server 2019中&#xff0c;先新建虚拟池&#xff0c;然后创建虚拟磁盘&#xff0c;记得添加磁盘类型要选择第三个&#xff0c;要不…

DFT mode下hard phy STA Nopath

hard Phy boundary No Path 1. shift mode; shift cornor出现No Path的; PHY SI SO在shift mode必须有timing的path; 展示为No constrained path; check step: report_timing -though NO constrained path set timing_report_unconstrained true report again you will…

【工作记录】F12查看接口信息及postman中使用

可参考 详细教程&#xff1a;如何从前端查看调用接口、传参及返回结果&#xff08;附带图片案例&#xff09;_f12查看接口及参数-CSDN博客 1、接口信息 接口基础知识2&#xff1a;http通信的组成_接口请求信息包括-CSDN博客 HTTP类型接口之请求&响应详解 - 三叔测试笔记…

《自然》:陆地蒸散量研究的统计失误被撤回-空间加权平均的计算方法

文章目录 前言一、空间加权平均的计算方法二、代码1.Python 实现2.MATLAB代码 前言 In this article, we calculated global land evapotranspiration for 2003 to 2019 using a mass-balance approach. To do this, we calculated evapotranspiration as the residual of the…

开源软件许可证冲突的原因和解决方法

1、什么是开源许可证以及许可证冲突产生的问题 开源软件许可证是一种法律文件&#xff0c;它规定了软件用户、分发者和修改者使用、复制、修改和分发开源软件的权利和义务。开源许可证是由软件的版权所有者&#xff08;通常是开发者或开发团队&#xff09;发布的&#xff0c;它…

【el-upload】el-upload组件 - list-type=“picture“ 时,文件预览展示优化

目录 问题图el-upload预览组件 PicturePreview效果展示 问题图 el-upload <el-uploadref"upload"multipledragaction"#":auto-upload"false":file-list"fileList"name"files":accept".png,.jpg,.jpeg,.JGP,.JPEG,.…

微前端 qiankun vite vue3

文章目录 简介主应用 qiankun-main vue3 vite子应用 qiankun-app-vue2 webpack5子应用 qiankun-react webpack5子应用 quankun-vue3 vite遇到的问题 简介 主要介绍以qiankun框架为基础&#xff0c;vite 搭建vue3 项目为主应用&#xff0c;wepack vue2 和 webpack react 搭建的…

C#从入门到精通(1)

目录 第一章 C#与VS介绍 第二章 第一个C#程序 &#xff08;1&#xff09;C#程序基本组成 1.命名空间 2.类 3.Main方法 4.注释 5.语句 6.标识符及关键字 &#xff08;2&#xff09;程序编写规范 1.代码编写规则 2.程序命名方法 3.元素命名规范 第三章 变量 &…

东隆科技携手PRIMES成立中国校准实验室,开启激光诊断高精度新时代

3月12日&#xff0c;上海慕尼黑光博会期间&#xff0c;东隆科技正式宣布与德国PRIMES共同成立“中国校准实验室”。这一重要合作标志着东隆科技在本地化服务领域的优势与PRIMES在激光光束诊断领域的顶尖技术深度融合&#xff0c;旨在为中国客户提供更快速、更高精度的服务以及本…

SysOM 可观测体系建设(一):万字长文解读低开销、高精度性能剖析工具livetrace

可观测性是一种通过分析系统输出结果并推断和衡量系统内部状态的能力。谈及可观测性一般包含几大功能&#xff1a;监控指标、链路追踪、告警日志&#xff0c;及 Continues Profiling 持续剖析能力。对于操作系统可观测&#xff0c;监控指标可以帮助查看各个子系统&#xff08;I…

网络安全设备配置与管理-实验4-防火墙AAA服务配置

实验4-p118防火墙AAA服务配置 从这个实验开始&#xff0c;每一个实验都是长篇大论&#x1f613; 不过有好兄弟会替我出手 注意&#xff1a;1. gns3.exe必须以管理员身份打开&#xff0c;否则ping不通虚拟机。 win10虚拟机无法做本次实验&#xff0c;必须用学校给的虚拟机。首…

路由Vue Router基本用法

路由的作用是根据URL来匹配对应的组件&#xff0c;并且无刷新切换模板的内容。vue.js中&#xff0c;可使用Vue Router来管理路由&#xff0c;让构建单页应用更加简单。 一、效果 二、实现 1.项目中安装Vue Router插件 pnpm install vue-routerlastest 2.main.js import { …

【Qt】Qt + Modbus 服务端学习笔记

《Qt Modbus 服务端学习笔记》 1.因为项目的需要&#xff0c;要写一个modbus通信&#xff0c;csdn上感觉有些回答&#xff0c;代码是人工智能生成的&#xff0c;有些细节不对。我这个经过实测&#xff0c;是可以直接用的。 首先要包含Qt 的相关模块 Qt Modbus 模块主要包含以…

CherryStudio + 火山引擎DeepSeek R1 告别服务器繁忙

CherryStudio 火山引擎DeepSeek R1 告别服务器繁忙 一、下载CherryStudio并安装 CherryStudio是功能强大的多模型桌面客户端&#xff0c;支持Windows、macOS和Linux系统。集成了多种主流的大语言模型&#xff08;如OpenAI、DeepSeek、Gemini等&#xff09;以及本地模型运行功…

Unity TextMeshPro中显示建筑特殊符号

示例&#xff1a;显示效果如图 实现步骤 1、下载 SJQY 字体库 2、导入字体&#xff1a;将 SJQY 字体文件&#xff08;如 .ttf 或 .otf 文件&#xff09;导入到 Unity 项目的 Assets 文件夹中。 3、创建 TMP 字体资产 方法一 方法二 选择刚导入的字体文件&#xff0c;在…

Windows Docker 报错: has no HTTPS proxy,换源

pull python 3.7报错&#xff1a; 尝试拉取Docker 测试库hello world也失败 尝试使用临时镜像源&#xff0c;可以成功拉取&#xff1a; sudo docker pull docker.m.daocloud.io/hello-world说明确实是网络问题&#xff0c;需要配置镜像源&#xff0c;为了方便&#xff0c;在d…

Git远程拉取和推送配置

Git进行远程代码拉取和推送时候提示配置user.name 和 user.email 背景&#xff1a;换新电脑后使用Git进行代码拉取和推送过程中&#xff0c;提示“Make sure you configure your “user.name” and “user.email” in git.”。这个配置针对git的正常使用仅需要配置一次&#xf…

详解string类+迭代器

迭代器 概念&#xff1a;在 C 中&#xff0c;迭代器是访问容器&#xff08;如数组、列表、向量、字符串等&#xff09;元素的一种方式。迭代器提供了一种统一的接口&#xff0c;使得你可以使用相同的代码来遍历不同类型的容器。迭代器本质上是一个指针或者指针的封装&#xff0…

小红书不绑定手机号会显示ip吗

小红书作为一个生活方式分享平台&#xff0c;拥有庞大的用户群体。在小红书上&#xff0c;用户可以分享自己的生活点滴、购物心得、美食体验等&#xff0c;与其他用户进行互动交流。最近&#xff0c;不少用户对于小红书是否会在不绑定手机号的情况下显示IP属地产生了疑问&#…