golang入门笔记——测试
测试类型:
单元测试:
规则:
1.所有测试文件以_test.go结尾
2.func Testxxx(*testing.T)
3.初始化逻辑放到TestMain中
运行:
go test [flags][packages]
Go语言中的测试依赖go test命令。
go test命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中
测试函数:
每个测试函数必须导入testing包,测试函数名必须以Test开头,测试函数的基本格式(签名)如下:
覆盖率:
显示代码覆盖率的命令
go test [flags][packages] --cover
1.一般覆盖率:50%~60%,较高覆盖率80%+
2.测试分支相互独立、全面覆盖
3.测试单元粒度足够小,函数单一职责
依赖:
Mock
1.快速mock函数:
为一个函数打桩
为一个方法打桩
monkey打桩实例:
代码实例:
package split_stringimport ("strings"
)//切割字符串
//example:
//abc,b=>[a c]
func Split(str string, sep string) []string {var ret=make([]string,0,strings.Count(str,sep)+1)//预先分配好内存index := strings.Index(str, sep)for index >= 0 {ret = append(ret, str[:index])str = str[index+len(sep):]index = strings.Index(str, sep)}if str != "" {ret = append(ret, str)}return ret
}func TestMain(m *testing.M){
//测试前:数据装载、配置初始化等前置工作code:=m.Run()//测试后,释放资源等收尾工作
os.Exist(code)
}
package split_stringimport ("reflect""testing"
)func TestSplit(t *testing.T) {ret := Split("babcbef", "b")want := []string{"", "a", "c", "ef"}if !reflect.DeepEqual(ret, want) {//测试用例失败了t.Errorf("want:%v but got:%v\n", want, ret)}
} //测试用例一func Test2Split(t *testing.T) {ret := Split("a:b:c", ":")want := []string{"a", "b", "c"}if !reflect.DeepEqual(ret, want) {t.Fatalf("want:%v but get:%v\n", want, ret)}
} //测试用例二//一次测试多个
func Test3Split(t *testing.T) {type testCase struct {str stringsep stringwant []string}testGroup := []testCase{testCase{"babcbef", "b", []string{"", "a", "c", "ef"}},testCase{"a:b:c", ":", []string{"a", "b", "c"}},testCase{"abcdef", "bc", []string{"a", "def"}},testCase{"沙河有沙又有河", "有", []string{"沙河", "沙又", "河"}},}for _, test := range testGroup {got := Split(test.str, test.sep)if !reflect.DeepEqual(got, test.want) {t.Fatalf("want:%#v got:%#v\n", test.want, got)}}
}//子测试
func Test4Split(t *testing.T) {if testing.Short(){t.Skip("short模式下会跳过测试用例")}type testCase struct {str stringsep stringwant []string}testGroup := map[string]testCase{"case 1": testCase{"babcbef", "b", []string{"", "a", "c", "ef"}},"case 2": testCase{"a:b:c", ":", []string{"a", "b", "c"}},"case 3": testCase{"abcdef", "bc", []string{"a", "def"}},"case 4": testCase{"沙河有沙又有河", "有", []string{"沙河", "沙又", "河"}},}for name, test := range testGroup {t.Run(name, func(t *testing.T) {t.Parallel() //将每个测试用例标记为能够彼此并行运行got := Split(test.str, test.sep)if !reflect.DeepEqual(got, test.want) {t.Fatalf("want:%#v got:%#v\n", test.want, got)}})}
} //会把每个map中的样例试结果都打印出来
func TestMain(m *testing.M) {//测试的入口函数m.Run()//测试开始
}
//在split_string终端下
go test //进行测试
go test -v//查看测试细节
go test -cover//语句覆盖率
go test -cover -coverprofile=cover.out//将测试结果生成文件
go tool -cover -html=cover.out //生成html文件来分析cover.out,绿色覆盖,红色未覆盖
//好的测试,测试函数覆盖率:100% 测试覆盖率:60%
go test -run=Sep -v //只运行测试函数名中带有Sep的测试
go test -short //会跳过某些耗时的测试用例
基准测试:
func BenchmarkSplit(b *testing.B){for i:=0;i<b.N;i++{//N不是一个固定的数,是使Split跑够1秒钟的一个数Split("a:b:c:d:e",":")}
}
go test -bench=Split
//goos: windows windows平台
// goarch: amd64 amd64位
// pkg: test/split_string
// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
// BenchmarkSplit-12 12核 3869991 执行次数 307.2 ns/op 307.2ns/次
// PASS
// ok test/split_string 1.539s
go test -bench=Split -benchmem //增加了查看对内存的申请情况
网络测试:
func TestHelloHandler(t *testing.T) {ln, err := net.Listen("tcp", "localhost:0")handleError(t, err)defer ln.Close()http.HandleFunc("/hello", HelloHandler)go http.Serve(ln, nil)resp, err := http.Get("http://" + ln.Addr().String() + "hello")handleError(t, err)defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)handleError(t, err)if string(body) != "hello world!" {t.Fatal("expected hello world,but got", string(body))}
}
1.优化代码,需要对当前代码分析
2.内置的测试框架提供了基准测试的能力
func BenchmarkSelect(b *testing.B) {InitServerIndex()b.ResetTimer() //定时器重置for i := 0; i < b.N; i++ {Select()}
}func BenchmarkSelectParallel(b *testing.B) {InitServerIndex()b.ResetTimer()b.RunParallel(func(pb *testing.PB) {for pb.Next() {Select()}})
}
SqlMock
mock的核心在于屏蔽上游细节,使用一些实现设定好的数据来模拟上游返回的数据
sqlmock就是在测试过程中,指定你期望(Expectations)执行的查询语句,以及假定的返回结果(WillReturnResult)
sqlmock库的安装:
go get github.com/DATA-DOG/go-sqlmock
sqlmock.New()返回一个标准的sql.DB结构体实例指针,这是一个数据库连接句柄。除此之外还返回了一个sqlmock.Sqlmock结构体实例
db, mock, err := sqlmock.New()if err != nil {t.Errorf("create sqlmock fail")}defer db.Close()mock.ExpectExec(`sql sentence`).WithArgs(sqlmock.AnyArg()).WillReturnResult(sqlmock.NewResult(1, 1))//ExpectExec里的sql sentence为期望执行的sql语句//WithArgs代表执行该语句所要带的参数//sqlmock.AnyArg()代表任意参数//WillReturnResult里面代表假定的返回//sqlmock.NewResult(1,1)代表自增主键为1,1条影响结果
gorm使用sqlmock测试时的示例
db, mock, err := sqlmock.New()
if nil != err {t.Fatalf("Init sqlmock failed, err %v", err)
}
defer db.Close()gormDB, err := gorm.Open(mysql.New(mysql.Config{SkipInitializeWithVersion: true,Conn: db,}), &gorm.Config{})
if err!=nil {t.Fatalf("Init DB with sqlmock failed, err %v", err)
} else {if db, err := database.KnodiDB.DB(); nil != err {db.SetMaxIdleConns(10)db.SetMaxOpenConns(10)db.Ping()}
}
增删改查 sqlmock示例
main.go
package mainimport ("database/sql"_ "github.com/go-sql-driver/mysql"
)type User struct {Id int64Username stringPassword string
}func recordStats(db *sql.DB, userID, productID int64) (err error) {tx, err := db.Begin()if err != nil {return}defer func() {switch err {case nil:err = tx.Commit()default:tx.Rollback()}}()if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil {return}if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil {return}return
}func recordQuery(db *sql.DB, userID int64) (user *User, err error) {row := db.QueryRow("SELECT * FROM user where id =?", userID)user = new(User)err = row.Scan(&user.Id, &user.Username, &user.Password)return
}func recordDelete(db *sql.DB, userID int64) (err error) {_, err = db.Exec("DELETE FROM user where id=?", userID)if err != nil {return}return
}func main() {// @NOTE: the real connection is not required for testsdb, err := sql.Open("mysql", "root@/blog")if err != nil {panic(err)}defer db.Close()if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil {panic(err)}
}
main_test.go
package mainimport ("fmt""regexp""testing""github.com/DATA-DOG/go-sqlmock"
)// a successful case
func TestShouldUpdateStats(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)}defer db.Close()mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectCommit()// now we execute our methodif err = recordStats(db, 2, 3); err != nil {t.Errorf("error was not expected while updating stats: %s", err)}// we make sure that all expectations were metif err := mock.ExpectationsWereMet(); err != nil {t.Errorf("there were unfulfilled expectations: %s", err)}
}// a failing test case
func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)}defer db.Close()mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnError(fmt.Errorf("some error"))mock.ExpectRollback()// now we execute our methodif err = recordStats(db, 2, 3); err == nil {t.Errorf("was expecting an error, but there was none")}// we make sure that all expectations were metif err := mock.ExpectationsWereMet(); err != nil {t.Errorf("there were unfulfilled expectations: %s", err)}
}func TestQuery(t *testing.T) {userInfo := []string{"id","username","password",}db, mock, err := sqlmock.New()if err != nil {t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)}mock.ExpectQuery(regexp.QuoteMeta("SELECT * FROM user")).WithArgs(1).WillReturnRows(sqlmock.NewRows(userInfo).AddRow(1, "zyj", "123"))if err = recordStats(db, 2, 3); err == nil {t.Errorf("was expecting an error, but there was none")}user, err := recordQuery(db, 1)if err != nil || user == nil {t.Errorf("this is something wrong")}t.Log(user)
}func TestDelete(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)}mock.ExpectExec("DELETE FROM user").WithArgs(1).WillReturnResult(sqlmock.NewResult(1, 1))err = recordDelete(db, 1)if err != nil {t.Errorf("this is something wrong")}
}
ginkgo和gomega
1.在引入ginkgo和gomega的时候前面加.这样每次调用时就可以直接使用包中的方法函数了。
2.ginkgo使用Describe()来描述这段代码的行为,使用Context()来描述表达该行为是在不同的环境下执行,一个it就是一个spec即一个测试用例
3.ginkgo使用BeforeEach()来为specs设置状态,并使用It()来指定单个spec,也是一个测试用例,且执行每一个It模块前都会执行一次Describe的BeforeEach和AfterEach,以确保每个Specs都处于原始状态
4.JustBeforeEach()模块在所有BeforeEach()模块执行之后,It模块执行之前运行,BeforeSuit函数在所有Specs运行前执行,AfterSuite函数在所有Specs运行后执行,不论测试是否失败
5.使用Gomega中的Expect()函数来设置期望
package mainimport ("database/sql""fmt""regexp""sync""github.com/DATA-DOG/go-sqlmock". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Record Test", func() {var (once sync.Oncemock sqlmock.Sqlmockdb *sql.DBerr erroruserInfo []string)BeforeEach(func() {once.Do(func() {db, mock, err = sqlmock.New()if err != nil {fmt.Println(err)}})userInfo = []string{"id","username","password",}})Context("test update and insert", func() {It("text update and insert success", func() {mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectCommit()// now we execute our methoderr = recordStats(db, 2, 3)Expect(err).To(BeNil())// we make sure that all expectations were meterr = mock.ExpectationsWereMet()Expect(err).To(BeNil())})It("text update and insert failed", func() {mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnError(fmt.Errorf("some error"))mock.ExpectRollback()// now we execute our methoderr = recordStats(db, 2, 3)Expect(err).To(BeNil())// we make sure that all expectations were meterr := mock.ExpectationsWereMet()Expect(err).To(BeNil())})Context("test query", func() {It("test query", func() {mock.ExpectQuery(regexp.QuoteMeta("SELECT * FROM user")).WithArgs(1).WillReturnRows(sqlmock.NewRows(userInfo).AddRow(1, "zyj", "123"))err = recordStats(db, 2, 3)Expect(err).To(BeNil())user, err := recordQuery(db, 1)Expect(err).To(BeNil())Expect(user.Id).To(Equal(int64(1)))})})Context("text delete", func() {It("test delete", func() {mock.ExpectExec("DELETE FROM user").WithArgs(1).WillReturnResult(sqlmock.NewResult(1, 1))err = recordDelete(db, 1)Expect(err).To(BeNil())})})})
})
RedisMock
redismock的安装:
go get github.com/go-redis/redismock/v9
简单示例:
main.go
package mainimport ("context""fmt""time""github.com/redis/go-redis/v9"
)func NewsInfoForCache(redisDB *redis.Client, newsID int) (info string, err error) {cacheKey := fmt.Sprintf("news_redis_cache_%d", newsID)ctx := context.TODO()info, err = redisDB.Get(ctx, cacheKey).Result()if err == redis.Nil {// info, err = call api()info = "test"err = redisDB.Set(ctx, cacheKey, info, 30*time.Minute).Err()}return
}
main_test.go
package mainimport ("errors""fmt""sync""time""github.com/go-redis/redismock/v9". "github.com/onsi/ginkgo". "github.com/onsi/gomega""github.com/redis/go-redis/v9"
)var _ = Describe("Record Test", func() {var (once sync.Oncemock redismock.ClientMockredisClient *redis.Client)BeforeEach(func() {once.Do(func() {redisClient, mock = redismock.NewClientMock()})})Context("test set", func() {id := 123key := fmt.Sprintf("new_redis_cache_%d", id)It("test set success", func() {mock.ExpectGet(key).RedisNil()mock.Regexp().ExpectSet(key, `[a-z]+`, 30*time.Second).SetErr(errors.New("FAIL"))_, err := NewsInfoForCache(redisClient, id)Expect(err).To(BeNil())})})})
Monkey
monkey是go语言非常常用的一个打桩工具,它在运行时通过汇编语言重写可执行文件,将目标函数或方法的实现跳转到桩实现。
monkey库很强大,但是使用时需注意以下事项:
1.monkey不支持内联函数,在测试的时候需要通过命令行参数-gcflags=-1关闭Go语言的内联优化
2.monkey不是线程安全的,所以不能把它放到并发的单元测试中
安装monkey库的命令:
go get bou.ke/monkey
简单的monkey打桩示例:
main.go
package mainimport ("fmt"
)type Student struct {
}func (S *Student) GetInfoByUID(id int64) (string, error) {return "", nil
}func MyFunc(uid int64) string {var varys Studentu, err := varys.GetInfoByUID(uid)if err != nil {return "welcome"}// 这里是一些逻辑代码...return fmt.Sprintf("hello %s\n", u)
}
main_test.go
package mainimport ("bou.ke/monkey". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Record Test", func() {Context("test myfunc", func() {var varys Studentmonkey.Patch(varys.GetInfoByUID, func(num int64) (string, error) {return "zyj", nil})ret := MyFunc(123)Expect(ret).NotTo(Equal("welcome"))})})
相关文章:

golang入门笔记——测试
测试类型: 单元测试: 规则: 1.所有测试文件以_test.go结尾 2.func Testxxx(*testing.T) 3.初始化逻辑放到TestMain中 运行: go test [flags][packages]Go语言中的测试依赖go test命令。 go test命令是一…...
【CSAPP】整数运算
文章目录无符号加法练习1练习2补码加法练习1练习2练习3练习4补码的非练习无符号乘法补码乘法练习1练习2练习3乘以常数练习1练习2除以2的幂练习1练习2关于整数运算的最后思考练习无符号加法 考虑两个非负整数x和y,满足0≤x,y<2w0 \le x, y < 2^w0≤x,y<2w&…...

使用 xshell 远程连接(使用 xftp 远程传输)
xshell 和 xftp的使用都基于ssh协议,我们需要先在远程服务端或者虚拟机上安装ssh服务,然后才能远程连接。 目录 1、什么是ssh协议? 2、安装 openssh (1) 安装 openssh 服务器 (2) 关闭服务器防火墙(或者开放端口22)…...
一个例子搞懂子网划分及子网掩码的计算
前置知识: 1、标准ip地址分为A、B、C、D、E五类,分类标准是ip地址的前几个比特位的值。 我们知道ip地址是32位比特-4字节组成,A类地址则是由首位为0,首字节为网络地址,其余3字节为主机地址组成,A类网络地址…...

SPI机制源码:JDK Dubbo Spring
JDK 17 Dubbo 3.1.6 JDK SPI JDK SPI在sql驱动类加载、以及slf4j日志实现加载方面有具体实现。 示例 public class Test {private static final Logger logger LoggerFactory.getLogger(Test.class);public static void main(String[] args) {ServiceLoader<JdkSpiServi…...

Spring Security+jwt+redis+自定义认证逻辑 权限控制
Spring Securityjwtredis自定义认证逻辑 权限控制 1.拦截访问基本思路 2.创建数据库表:角色表(应该6个表,这里只用用户表代替角色表)、权限表、路径表、角色-权限表、权限-路径表 /* SQLyog Professional v12.14 (64 bit) MySQL…...

打游戏什么蓝牙耳机好用?打游戏比较好的蓝牙耳机
游戏耳机提供身临其境的细致声音,同时也是与朋友在线聊天的绝佳通信设备,尤其对于游戏玩家来说,聆听和被聆听的最佳方式之一就是游戏耳机,那2023年到底有哪些值得购买的游戏耳机呢?现在就让我们一起来看看吧。 第一款…...

炔基点击交联试剂1704097-05-1,Alkyne-A-DSBSO crosslinker,发生相应点击反应
1、理论分析:中文名:炔基-A-DSBSO crosslinker,英文名:Alkyne-A-DSBSO crosslinkerCAS号:1704097-05-1化学式:C25H32N2O12S2分子量:616.652、产品详情:外观:白色固体&…...
刷题记录:牛客NC24309Overplanting (Silver)
传送门:牛客 题目描述: Farmer John has purchased a new machine that is capable of planting grass within any rectangular region of his farm that is "axially aligned" (i.e., with vertical and horizontal sides). Unfortunately, the machine malfunc…...

Spring Boot中使用Sa-Token实现轻量级登录与鉴权
1. Sa-Token 介绍 Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。 功能结构图 2. 登录认证 对于一些登录之后才能访问的接口(例如&…...

《分布式技术原理与算法解析》学习笔记Day20
CAP理论 什么是CAP理论? CAP理论用来指导分布式系统设计,以保证系统的可用性、数据一致性等。 C,Consistency,一致性,指所有节点在同一时刻的数据是相同的,即更新操作执行结束并响应用户完成后ÿ…...

【2023-2-23】FastDeploy 安装教程
【2023-2-22】FastDeploy 安装编译教程 该测试 FastDeploy CPU版本。 1. fastDeploy库编译 1.1 官方预编译库下载 预编译库下载安装 1.2 自定义CPU版本库编译 官方编译FastDeploy教程 CMakeGUI VS 2019 IDE编译FastDeploy 本人编译教程 CMAKE_CONFIGURATION_TYPES 属性设…...
rollup.js 一个简单实用的打包工具
最近在看vue3相关的知识的时候,发现了一个新的打包工具,至少于我而言是新鲜的。它就是rollup.js。一说到JS打包、合并、压缩、模块处理等都会想到webpack,这是王者,当然入门的难度偏高。而vue3中搭配的vite运行速度确实非常快&…...

数据结构与算法之最小爬楼梯费用动态规划
继续上一道题目,在上一道题目的基础之上,我们来解决这一道爬楼梯最小费用题。一.题目描述二.思路(动态规划五部曲)确定dp数组以及下标的含义使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了。dp[i]的…...
阿里云ACA认证如何获取?
获取阿里云ACA(Alibaba Cloud Certification Associate)认证,需要按照以下步骤进行操作: 注册阿里云账号。如果您还没有阿里云账号,请先注册一个账号。登录阿里云官网。登录后,进入阿里云认证中心。选择AC…...

【Python入门第十六天】Python If ... Else
Python 条件和 If 语句 Python 支持来自数学的常用逻辑条件: 等于:a b不等于:a ! b小于:a < b小于等于:a < b大于:a > b大于等于:a > b 这些条件能够以多种方式使用,…...
两数之和的解法
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案…...

领导催我优化SQL语句,我求助了ChatGPT。这是ChatGPT给出的建议,你们觉得靠谱吗
作为一个程序员,无论在面试还是工作中,优化SQL都是绕不过去的难题。 为啥?工作之后才会明白,随着公司的业务量增多,SQL的执行效率对程系统运行效率的影响逐渐增大,相对于改造代码,优化SQL语句是…...

ArcGIS手动分割矢量面要素从而划分为多个面部分的方式:Cut Polygons Tool
本文介绍在ArcGIS下属ArcMap软件中,通过“Cut Polygons Tool”工具,对一个面要素矢量图层加以手动分割,从而将其划分为指定形状的多个部分的方法。 对于一个面要素矢量文件,有时我们需要对其加以划分,通过手动勾勒新的…...

【LeetCode】剑指 Offer 13. 机器人的运动范围 p92 -- Java Version
题目链接:https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/ 1. 题目介绍(13. 机器人的运动范围) 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动࿰…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...