go语言中的切片详解
1.概念
在Go语言中,切片(Slice)是一种基于数组的更高级的数据结构,它提供了一种灵活、动态的方式来处理序列数据。切片在Go中非常常用,因为它们可以动态地增长和缩小,这使得它们比固定大小的数组更加灵活。
2.切片的内部实现
切片是对数组的抽象表示,它包含三个要素:
1. 指向底层数组的指针
2. 切片的长度(元素数量)
3. 切片的容量(从开始到底层数组末尾的元素数量)
切片是一个有三个字段的数据结构,这些数据结构包含 Golang 需要操作底层数组的元数据:
这 3 个字段分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)。
3.切片创建和初始化
在 Golang 中可以通过多种方式创建和初始化切片。是否提前知道切片所需的容量通常会决定如何创建切片。
通过 make() 函数创建切片
使用 Golang 内置的 make() 函数创建切片,此时需要传入一个参数来指定切片的长度:
slice := make([]int, length, capacity)
这里,length是切片的长度,capacity是切片的容量。如果未指定capacity,它将等于length。
// 创建一个整型切片
// 其长度和容量都是 5 个元素
slice := make([]int, 5)
分别指定长度和容量时,创建的切片,底层数组的长度是指定的容量,但是初始化后并不能
访问所有的数组元素。
注意,Golang 不允许创建容量小于长度的切片,当创建的切片容量小于长度时会在编译时刻报错:
// 创建一个整型切片
// 使其长度大于容量
myNum := make([]int, 5, 3)
分别指定长度和容量时,创建的切片,底层数组的长度是指定的容量,但是初始化后并不能
访问所有的数组元素。
注意,Golang 不允许创建容量小于长度的切片,当创建的切片容量小于长度时会在编译时刻报错
4.通过字面量创建切片
另一种常用的创建切片的方法是使用切片字面量,这种方法和创建数组类似,只是不需要指定[]运算符里的值。初始的长度和容量会基于初始化时提供的元素的个数确定:
// 创建字符串切片
// 其长度和容量都是 3 个元素
myStr := []string{"Jack", "Mark", "Nick"}
// 创建一个整型切片
// 其长度和容量都是 4 个元素
myNum := []int{10, 20, 30, 40}
当使用切片字面量创建切片时,还可以设置初始长度和容量。要做的就是在初始化时给出所需的长度和容量作为索引。下面的语法展示了如何使用索引方式创建长度和容量都是100个元素的切片:
// 创建字符串切片
// 使用空字符串初始化第 100 个元素
myStr := []string{99: ""}
区分数组的声明和切片的声明方式
当使用字面量来声明切片时,其语法与使用字面量声明数组非常相似。二者的区别是:如果在 [] 运算符里指定了一个值,那么创建的就是数组而不是切片。只有在 [] 中不指定值的时候,创建的才是切片。看下面的例子:
// 创建有 3 个元素的整型数组
myArray := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
mySlice := []int{10, 20, 30}
切片的复制:
当你有一个切片或者数组的时候,当希望将其元素作为单独的参数传递给一个函数时候,可以使用...操作符
func sum(x, y, z int) int {return x + y + z
}numbers := []int{1, 2, 3}
result := sum(numbers...) // 将 numbers 切片中的元素作为参数传递给 sum 函数
fmt.Println(result) // 输出: 6
在这个例子中,numbers...将切片numbers中的元素1,2,3展开为sum函数的参数
5.nil 和空切片
有时,程序可能需要声明一个值为 nil 的切片(也称nil切片)。只要在声明时不做任何初始化,就会创建一个 nil 切片
// 创建 nil 整型切片
var myNum []int
在 Golang 中,nil 切片是很常见的创建切片的方法。nil 切片可以用于很多标准库和内置函数。在需要描述一个不存在的切片时,nil 切片会很好用。比如,函数要求返回一个切片但是发生异常的时候。下图描述了 nil 切片的状态:
空切片和 nil 切片稍有不同,下面的代码分别通过 make() 函数和字面量的方式创建空切片:
// 使用 make 创建空的整型切片
myNum := make([]int, 0)
// 使用切片字面量创建空的整型切片
myNum := []int{}
区别:
1. 内存分配:
• nil 切片:没有指向任何底层数组,没有任何内存分配。
• 空切片:指向一个长度为0的底层数组,但这个数组可能已经分配了内存(尽管长度为0)。
2. 函数返回值:
• 使用 nil 可以表示“没有值”,这在错误处理和可选值中很有用。
• 空切片通常用于表示一个有效的切片,但当前没有元素。
package main
import "fmt"func main() {//创建一个空切片emptySlice :=make([]int,0)fmt.Println(emptySlice)//创建一个nil切片var nilSlice []intfmt.Println(nilSlice)//检查切片是否为空if len(emptySlice) == 0 {fmt.Println("emptySlice is empty")}if nilSlice == nil {fmt.Println("nilSlice is nil")}//尝试访问空切片的元素if len(emptySlice) > 0 {fmt.Println(emptySlice[0])}else {fmt.Println("emptySlice is empty")}}
• emptySlice是一个空切片,它有长度0,但是它指向一个内存地址。
• nilSlice是一个nil指针,它没有指向任何内存地址,因此不能用来访问任何元素。
尝试访问nil切片的元素会导致程序崩溃(panic),因为nil没有指向有效的内存。而空切片虽然长度为0,但是它是指向一个有效的内存地址的,所以可以安全地对其进行操作,比如扩展或赋值。
6.为切片中的元素赋值
对切片里某个索引指向的元素赋值和对数组里某个索引指向的元素赋值的方法完全一样。使
用 [] 操作符就可以改变某个元素的值,下面是使用切片字面量来声明切片:
// 创建一个整型切片
// 其容量和长度都是 5 个元素
myNum := []int{10, 20, 30, 40, 50}
// 改变索引为 1 的元素的值
myNum [1] = 25
切片之所以被称为切片,是因为创建一个新的切片,也就是把底层数组切出一部分。通过切片创建新切片的语法如下:
slice[i:j]
slice[i:j:k]
其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。下面是几种常见的简写形式:
slice[i:] // 从 i 切到最尾部
slice[:j] // 从最开头切到 j(不包含 j)
slice[:] // 从头切到尾,等价于复制整个 slice
让我们通过下面的例子来理解通过切片创建新的切片的本质:
// 创建一个整型切片
// 其长度和容量都是 5 个元素
myNum := []int{10, 20, 30, 40, 50}
// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newNum := slice[1:3]
执行上面的代码后,我们有了两个切片,它们共享同一段底层数组,但通过不同的切片会看到底层数组的不同部分:
下面是详细的用法:
package mainimport "fmt"func main() {// 创建一个原始切片original := []int{1, 2, 3, 4, 5}// 通过切片操作符创建新的切片a := original[:3] // 包含从索引0到索引2的元素b := original[2:] // 包含从索引2到末尾的元素c := original[:] // 创建一个新的切片,它是原始切片的一个副本// 修改原始切片original[0] = 10// 打印结果fmt.Println("Original slice:", original) // 输出: [10 2 3 4 5]fmt.Println("Slice a:", a) // 输出: [1 2 3]fmt.Println("Slice b:", b) // 输出: [3 4 5]fmt.Println("Slice c:", c) // 输出: [1 2 3 4 5]// 修改新的切片aa[0] = 100// 打印结果fmt.Println("Original slice after modifying a:", original) // 输出: [10 2 3 4 5]fmt.Println("Slice a after modification:", a) // 输出: [100 2 3]
}
共享底层数组的切片
需要注意的是:现在两个切片 myNum 和 newNum 共享同一个底层数组。如果一个切片修改了该底层数组的共享
部分,另一个切片也能感知到(请参考前图):
在Go语言中,切片是引用类型,这意味着它们指向底层数组的连续区域。当你通过切片操作创建一个新的切片时,新切片和原始切片可能共享同一个底层数组。如果新切片的容量足够,对新切片的修改可能会反映到原始切片上,因为它们可能指向相同的底层数组元素。
如果你需要一个与原始切片完全独立的副本,可以使用copy函数来创建一个新的底层数组。这样,对新数组的修改就不会影响原始数组。
下面是一个详细的示例,展示了如何使用copy函数创建一个完全独立的切片副本,并解释了为什么这样做可以避免对原始切片的意外修改。
package mainimport "fmt"func main() {original := []int{1,2,3,4,5}//使用切片操作符创建一个新的切片,它与原始切片共享同一个底层数组sharedSlice := original[:]independentSlice :=make([]int, len(original))copy(independentSlice, original)// 打印原始切片和两个新切片的内容fmt.Println("Original slice:", original) // 输出: [1 2 3 4 5]fmt.Println("Shared slice:", sharedSlice) // 输出: [1 2 3 4 5]fmt.Println("Independent slice:", independentSlice) // 输出: [1 2 3 4 5]//修改原始切片original[0] = 10fmt.Println("Modified original slice:", original) // 输出: [10 2 3 4 5]fmt.Println("Shared slice after modification:", sharedSlice) // 输出: [10 2 3 4 5]//修改独立切片independentSlice[0] = 20fmt.Println("Independent slice after modification:", independentSlice) // 输出: [20 2 3 4 5]//修改独立切片之后,原始切片不受影响fmt.Println("Original slice after independent modification:", original) // 输出: [10 2 3 4 5]fmt.Println("Shared slice after independent modification:", sharedSlice) // 输出: [10 2 3 4 5]}
代码运行结果:
7.切片扩容
Go 语言中的切片(slice)是一种动态数组,它允许你动态地增长和缩小。当你向切片添加元素,而切片的容量(capacity)不足以容纳更多元素时,Go 语言会自动进行扩容。扩容的具体机制如下:
- 1. 初始容量:当你创建一个新的切片时,它会有一个初始的容量。如果你通过 make 函数创建切片,你可以指定切片的长度(length)和容量(capacity)。
- 2. 扩容机制:当你向切片添加元素,超出当前容量时,Go 语言会进行扩容。扩容通常遵循以下规则:
- 扩容后的容量通常是原容量的两倍,但具体增长因子可能因实现而异。
- 如果切片的容量已经很大,扩容可能不会简单地翻倍,而是增加一个固定的数量。
- 3. 扩容过程:扩容时,Go 语言会分配一个新的数组,并将原切片中的元素复制到新数组中。然后,新元素会被添加到新数组中。最后,切片的底层数组指针会被更新为指向新数组。
- 4. 性能考虑:频繁的扩容可能会导致性能问题,因为每次扩容都需要分配新的内存并复制元素。为了避免这种情况,你可以通过预先分配足够的容量来减少扩容的次数。
- 5. 手动扩容:虽然 Go 语言会自动管理切片的扩容,但你也可以手动扩容切片。例如,你可以使用 append 函数来添加元素,或者使用 copy 函数和新的切片来手动复制元素。
下面是一个简单的 Go 语言切片扩容的:
package mainimport "fmt"func main() {s := make([]int, 0, 1) // 创建一个长度为0,容量为1的切片for i := 0; i < 5; i++ {s = append(s, i) // 向切片添加元素fmt.Printf("len=%d cap=%d slice=%v\n", len(s), cap(s), s)}
}
运行结果:
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=3 cap=4 slice=[0 1 2]
len=4 cap=4 slice=[0 1 2 3]
len=5 cap=8 slice=[0 1 2 3 4]
函数 append() 会智能地处理底层数组的容量增长。在切片的容量小于 1000 个元素时,总是会成倍地增加容量。一旦元素个数超过 1000,容量的增长因子会设为 1.25,也就是会每次增加 25%的容量(随着语言的演化,这种增长算法可能会有所改变)。
8.遍历切片
8.1使用for循环和索引
package mainimport "fmt"func main() {slice := []int{10, 20, 30, 40, 50}for i := 0; i < len(slice); i++ {fmt.Println("Element at index", i, "is", slice[i])}
}
8.2 使用for循环和range
使用range关键字可以同时获取索引和值,这是遍历切片的常用方法
package mainimport "fmt"func main() {slice :=[]int{10,20,30,40,50}for index,value := range slice{fmt.Printf("Index is %d and value is %d\n",index,value)}
}
8.3 使用 for 循环和 range(只获取值)
如果你不需要索引,只关心值,可以使用以下方式简化代码。
用以下方式简化代码。
package mainimport "fmt"func main() {slice := []int{10, 20, 30, 40, 50}for _, value := range slice {fmt.Println("Value is", value)}
}
8.4 使用 for 循环和 range(只获取索引)
如果你只需要索引,可以使用下划线 _ 忽略值。
package mainimport "fmt"func main() {slice := []int{10, 20, 30, 40, 50}for index, _ := range slice {fmt.Println("Index is", index)}
}
8.5 使用 for 循环和 range(遍历字符串切片)
对于字符串切片,range 会返回每个字符串中的每个字符(作为 rune 类型)。
package mainimport "fmt"func main() {slice := []string{"hello", "world"}for _, word := range slice {for _, char := range word {fmt.Printf("%c ", char)}fmt.Println()}
}
9.切片操作
9.1 使用copy函数
copy 函数是标准库 copy 包中提供的一个函数,用于将一个切片的内容复制到另一个切片中。它接受两个切片作为参数:源切片和目标切片,并返回复制的元素数量。
package mainimport "fmt"func main() {src :=[]int{1,2,3,4,5}dst :=make([]int,5)//从src复制到dstcopied :=copy(dst,src)fmt.Println("Copied element",copied)fmt.Println("Destination",dst)
}
9.2 使用 append 函数
- 第一个参数是目标切片,用于接收新添加的元素。
- 后续参数是要添加到切片中的元素。
- 使用 append 进行切片复制
- 在 append([]int(nil), original...) 中:
- []int(nil) 创建了一个类型为 []int 的空切片。这个切片的长度和容量都是0。
- original... 是 Go 语言的变参语法,它将 original 切片中的所有元素作为独立的参数传递给 append 函数。
package mainimport "fmt"func main() {original := []int{1, 2, 3, 4, 5}copy := append([]int(nil), original...)fmt.Println("Original slice:", original)fmt.Println("Copy slice:", copy)
}
在这个例子中,copy 切片是通过 append 函数创建的,它包含了 original 切片的所有元素。这种方法不仅代码简洁,而且性能也很好,因为它避免了不必要的内存分配和复制操作。
总结来说,append([]int(nil), original...) 是一种利用 append 函数的灵活性和智能内存管理来高效复制切片的方法。
9.3手动复制
你也可以通过遍历源切片并手动将每个元素赋值到新的切片中来实现复制。
package mainimport ("fmt"
)func main() {src := []int{1, 2, 3, 4, 5}dst := make([]int, len(src)) // 创建一个相同长度的新切片for i := range src {dst[i] = src[i]}fmt.Println("Source slice:", src)fmt.Println("Destination slice:", dst)
}
这种方法虽然直接,但效率较低,特别是对于大型切片。
注意事项
• 当使用 copy 函数时,确保目标切片有足够的容量来接收所有元素,否则它只会复制目标切片的容量允许的部分。
• 使用 append 函数时,虽然方便,但可能会因为扩容操作而增加额外的性能开销。
• 手动复制虽然控制更精细,但代码更复杂,且容易出错。
在实际应用中,选择哪种方法取决于具体的需求和性能考虑。对于大多数情况,copy 函数提供了一个简单而高效的方式来复制切片。
相关文章:

go语言中的切片详解
1.概念 在Go语言中,切片(Slice)是一种基于数组的更高级的数据结构,它提供了一种灵活、动态的方式来处理序列数据。切片在Go中非常常用,因为它们可以动态地增长和缩小,这使得它们比固定大小的数组更加灵活。…...

ElK 8 收集 Nginx 日志
1. 说明 elk 版本:8.15.0 2. 启个 nginx 有 nginx 可以直接使用。我这里是在之前环境下 docker-compose.yml 中启动了个 nginx: nginx:restart: alwaysimage: nginx:1.26.1ports:- "80:80"- "443:443"volumes:#- ./nginx/html:/…...

Xv6驱动(四):CLINT
阅读材料 Xv6代码:memlayout.h、start.c、kernelvec.S教材5.4节 CLINT内存映射 实际上,CLINT还包括若干个MSIP寄存器,用来触发软件中断,但是在Xv6中不考虑软件中断,因此这些寄存器也不用考虑 // core local interr…...

【LInux】HTTPS是如何实现安全传输的
1. 客户端发起HTTPS连接请求 当浏览器请求一个HTTPS网址时,客户端(例如浏览器)会向服务器发起一个HTTPS请求。 2. 服务器返回数字证书 服务器收到请求后,会向客户端发送包含公钥的数字证书。数字证书由**权威认证机构ÿ…...

英飞凌PSoC4000T的GPIO中断示例工程
关于PSoC4000T的初步介绍见:英飞凌MCU第五代高性能CAPSENSE技术PSoC4000T_psoc 4000t-CSDN博客 下面这个工程,在modustoolbox中可编译、下载到开发板、debug调试。 编译时会用到mtb_shared这个库: 已经pdl这个periperal driver library库:...

物联网(IoT)中基于深度学习的入侵检测系统的综合综述
这篇论文是一篇全面的综述,标题为“A comprehensive survey on deep learning-based intrusion detection systems in Internet of Things (IoT)”,作者是Qasem Abu Al-Haija和Ayat Droos。论文主要探讨了在物联网(IoT)环境中基于深度学习的入侵检测系统…...

《成都体育学院学报》
投稿指南 成都体育学院学报属于体育类型期刊,由成都体育学院主办,国内统一刊号:51-1097/G8,国际标准刊号:1001-9154,双月,面向国内外公开发行。 一、来稿必须是作者独立取得的原创性学术研究成…...

Flask-JWT-Extended登录验证, 不用自定义
"""安装:pip install Flask-JWT-Extended创建对象 初始化与app绑定jwt JWTManager(app) # 初始化JWTManager设置 Cookie 的选项:除了设置 cookie 的名称和值之外,你还可以指定其他的选项,例如:过期时间 (max_age)࿱…...

rpm 与 yum
11 rpm -qa | grep openssh rpm与 yum CentOS仅删除软件包本身而不删除依赖 https://blog.csdn.net/kangshuaibi/article/details/125472204...

几种修改docker默认存储位置的方法
需求 docker容器存放目录磁盘空间满了,需要转移数据,修改Docker默认存储位置 解决方法 方法1:迁移到新目录 停止docker服务。 1systemctl stop docker; //每个liunx版本的命令不一样。创建新的docker目录,执行命令df…...

istio中如何使用serviceentry引入外部服务
假设需要引入一个外部服务,外部服务ip为10.10.102.90,端口为32033. 引入到istio中后,我想通过域名gindemo.test.ch:9090来访问这个服务。 serviceentry yaml内容如下: apiVersion: networking.istio.io/v1beta1 kind: ServiceEn…...

模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性
先看抖音的格式 对ID加密的格式 MB4EENgLILJPeQKhJht-rjcc6y0ECMk_RGTceg6JBAA 需求是 同一个ID 比如 413884936367560 每次获取得到的加密ID都是不同的,最终解密的ID都是413884936367560 注意这是一个加密后可解密原文的方式,不是单向加密 那么如下进行…...

solidwork镜像实体
效果如下: 可以看到这两条线是对称的。 第一步,点击这条要镜像的边,接着点击镜像实体。 然后选择镜像轴,即可...

第6天:趋势轮动策略开发(年化18.8%,大小盘轮动加择时)
原创内容第655篇,专注量化投资、个人成长与财富自由。 轮动策略是一种投资策略,它涉及在不同的资产类别、行业或市场之间进行切换,以捕捉市场机会并优化投资组合的表现。 这种策略的核心在于识别并利用不同资产或市场的相对强弱,…...

米客方德SD NAND 掉电测试
SD NAND 异常上下电测试的作用 SD NAND 异常上下电测试是一项关键的测试步骤,对确保SD NAND在不同电源条件下的稳定性和可靠性至关重要。 通过模拟正常和异常电源情况,测试可以验证设备的电源管理功能、检测潜在错误和异常行为,并评估设备在…...

深入探索Android开发之Kotlin核心技术学习大全
Android作为全球最流行的移动操作系统之一,其开发技能的需求日益增长。本文将为您介绍一套专为Android开发者设计的Kotlin核心技术学习资料,包括详细的学习大纲、PDF文档、源代码以及配套视频教程,帮助您从Kotlin基础到高级特性,再…...

langchain报错记录(js)
文章目录 [ERR_PACKAGE_PATH_NOT_EXPORTED]报错:报错语句:思路:解决方法: [ERR_PACKAGE_PATH_NOT_EXPORTED] 报错: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath ‘./dist/prompts/’ is not defined by…...

VSCode调试Unity准备工作
一.Unity设置VSCode为默认编辑器 Unity编辑器中Edit-Preferences-External Tools中选择VSCode 二.VSCode安装Unity插件 三.Unity的Visual Studio Editor升至最新 Window->Package Manager->Visual Studio Editor 四.下载配置.Net 8.0 安装之前VSCode会提示你下载.Net …...

缓存穿透 问题(缓存空对象)
文章目录 1、缓存穿透2、缓存空对象3、AlbumInfoApiController --》getAlbumInfo()4、AlbumInfoServiceImpl --》getAlbumInfo()5、RedisConstant6、请求缓存不存在的数据 1、缓存穿透 2、缓存空对象 3、AlbumInfoApiController --》getAlbumInfo() GetMapping("getAlbumI…...

Vue3:mitt实现组件通信
目录 一.性质 1.轻量级 2.单例 3.异步 4.事件绑定与解绑 二.作用 1.组件间通信 2.解耦 3.状态管理 4.事件的集中处理 三.使用 1.安装mitt 2.引入mitt;调用mitt;暴露mitt 3.组件1 4.组件2 四.代码 1.组件1 2.组件2 五.效果 一.性质 1…...

一个有个性的使用工具thefuck@Ubuntu
这个工具名字可能有些粗鄙,不过真的有让人眼前一亮的功能。 当用户输入错误的命令时,TheFuck会根据上下文自动推测并给出正确的命令建议。 安装 apt update apt search thefuck apt install thefuck 使用 在错误命令下面直接输入thefuck即可。 不过…...

【PyQt5】PyQt5桌面APP开发学习
跟我学习PyQt5之每天一更 1、兴趣是最好的坚持2、object基类3、QWidget子类 等我不更新了,就说明我学习完成了,有想学而又不会的可以催更留言! 1、兴趣是最好的坚持 看视频看书不如先来一个游戏玩一玩,学习由对他有兴趣开始 2024…...

JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操
JdbcTemplate是Spring框架中的一个重要组件,主要用于简化JDBC数据库操作。它提供了许多常用的方法,如查询、插入、更新、删除等。本文将介绍JdbcTemplate的常用方法及其使用方式,以及参数绑定和删除数据的方法。 一、JdbcTemplate常用方法 查…...

向日葵好用吗?4款稳定的远程控制软件推荐。
远程控制技术现在已经被应用于很多个领域,像企业办公,远程协助,智能家居,工业控制等等。我们常常会用到的时前两种。而实现远程控制的方式也有多种,但是最方便高效的还是使用第三方软件。我最常使用的是向日葵…...

【开源大模型生态9】百度的文心大模型
这张图展示了百度千帆大模型平台的功能架构及其与BML-AI开发平台和百度百舸AI异构计算平台的关系。以下是各个模块的解释: 模型广场: 通用大模型:提供基础的自然语言处理能力。行业大模型:针对不同行业的定制化模型。大模型工具链…...

CSS的三种基本选择器
使用CSS控制网页格式有行内法,内嵌式,链接式,导入式等方法 这里将采用内嵌式的方法书写 内嵌法就是通过<style>标记将样式定义在HTML的文件头部中 1.标记选择器 标记选择器特点:定义了标记选择器之后,网页中…...

排序学习笔记
目录 排序排序的相关概念冒泡排序插入排序选择排序堆排序快速排序归并排序 内排序和外排序非比较排序稳定性稳定性 完 排序 排序的相关概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起…...

【nginx】缓存配置文件
http {# ... 其他配置 ...# 缓存目录配置proxy_cache_path /var/cache/nginx/proxy_cache levels1:2 keys_zonemy_cache:10m inactive60m use_temp_pathoff;# ... 其他配置 ... }server {listen 80;server_name www.example.com;location / {root /var/www/example.com/public;…...

如何使用 maxwell 同步到 redis?
文章目录 1、MaxwellListener2、MxwObject1. 使用Maxwell捕获MySQL变更2. 将Maxwell的输出连接到消息系统3. 从消息系统读取数据并同步到Redis注意事项 1、MaxwellListener package com.atguigu.tingshu.album.listener;import com.alibaba.fastjson.JSON; import org.apache.…...

C++ 元编程
目录 C 元编程1. 术语2. 元函数1. 数值元函数示例:阶乘计算 2. 类型元函数示例:类型选择 3. 混合编程1. 常规的计算点积范例2. 混合元编程计算点积 4. typelist实现设计和基本操作接口(算法)完整代码 5. tuple 实现基础知识1. 左值…...