Golang学习历程【第五篇 复合数据类型:数组切片】

Golang学习历程【第五篇 复合数据类型:数组&切片】

  • 1. 数组(Array)
    • 1.1 数组的定义
    • 1.2 初始化数组
    • 1.3 数据的循环遍历
    • 1.4 多维数组
  • 2. 切片(Slice)
    • 2.1 切片声明、初始化
    • 2.2 基于数组创建切片
    • 2.2 切片的长度(len)和容量(cap)*
  • 3. nil值
  • 4. 值类型和引用数据类型
  • 5. 切片常用函数
    • 5.1 创建切片:make
    • 5.2 扩容切片:append
    • 5.3 复制切片【深克隆】:copy
    • 5.4 切片的删除
    • 5.5 sort排序
      • 5.5.1 升序排序
      • 5.5.2 降序排序
  • 6. 扩展技巧
    • 6.1 语法提示
    • 6.2 方法参数、含义使用探究

1. 数组(Array)

数组: 一系列固定长度同一类型数据的集合。数组为值类型

1.1 数组的定义

var 变量名 = [元素个数]<数据类型>
// 声明 + 初始化,此时可将[元素个数]替换为[...],表示初始化任意多个数据
var 变量名 = [元素个数]<数据类型>{}
变量名:= [元素个数]<数据类型>{}

示例:

// 数组的定义
var arr1 [4]int
// len获取数据长度
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)

结果:

类型:[4]int;   数组长度:4;    数据:[0 0 0 0]

1.2 初始化数组

// 数组的定义
var arr1 [4]int
// len获取数据长度
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
/* 数组初始化 */
// 1.方式一
arr1[0] = 1
arr1[3] = 4
fmt.Printf("方式一: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
// 2. 方式二 var 变量名 = [元素个数]<数据类型>{}
var arr2 = [3]float64{1, 2, 4.6}
fmt.Printf("方式二: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr2, len(arr2), arr2)
// 3. 方式三 变量名:= [元素个数]<数据类型>{}
arr3 := [3]string{"java", "Golang", "Python"}
fmt.Printf("方式三: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr3, len(arr3), arr3)
// 4. 方式四 var 变量名 = [...]<数据类型>{} 或 变量名:= [...]<数据类型>{}
arr4 := [...]int{2, 4, 6, 7, 8}
fmt.Printf("方式四: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr4, len(arr4), arr4)
// 5. 方式五 指定下标索引初始化索引
arr5 := [...]float64{0: 2, 2: 3.5, 5: 4.6, 7: 9}
fmt.Printf("方式五: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr5, len(arr5), arr5)

结果:

类型:[4]int;   数组长度:4;    数据:[0 0 0 0]
方式一: 类型:[4]int;   数组长度:4;    数据:[1 0 0 4]
方式二: 类型:[3]float64;       数组长度:3;    数据:[1 2 4.6]
方式三: 类型:[3]string;        数组长度:3;    数据:[java Golang Python] 
方式四: 类型:[5]int;   数组长度:5;    数据:[2 4 6 7 8]
方式五: 类型:[8]float64;       数组长度:8;    数据:[2 0 3.5 0 0 4.6 0 9]

1.3 数据的循环遍历

/* 数组的循环遍历 */
arr6 := [3]string{"java", "Golang", "Python"}
// 1. 使用fori循环
fmt.Printf("fori循环 ")
for i := 0; i < len(arr6); i++ {
	fmt.Printf("下标%v: 值:%v; \t", i, arr6[i])
}
fmt.Println()
// 2. 使用for range
fmt.Printf("for range循环 ")
for index, value := range arr6 {
	fmt.Printf("下标%v: 值:%v; \t", index, value)
}

结果:

fori循环 下标0: 值:java;       下标1: 值:Golang;      下标2: 值:Python;
for range循环 下标0: 值:java;  下标1: 值:Golang;      下标2: 值:Python;

1.4 多维数组

// 2维数组为例 var 变量名 = [行个数][列个数]数据类型{{}}
var arr7 = [3][3]int{
	{1, 2, 3}, // 每一行数据
	{4, 5, 6},
	{7, 8, 9},
}

fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr7, len(arr7), arr7)
// 可以忽略行的数据个数,列的数据个数不允许忽略
var arr8 = [...][2]string{
	{"a", "b"},
	{"c", "d"},
}
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr8, len(arr8), arr8)

// 二维数组循环
for i := 0; i < len(arr7); i++ {
	for j := 0; j < len(arr7[i]); j++ {
		fmt.Printf("%v行%v列: 值:%v; \t", i+1, j+1, arr7[i][j])
	}
	fmt.Println()
}
for row, rowValue := range arr8 {
	for col, value := range rowValue {
		fmt.Printf("%v行%v列: 值:%v; \t", row+1, col+1, value)
	}
	fmt.Println()
}

结果:

类型:[3][3]int;        数组长度:3;    数据:[[1 2 3] [4 5 6] [7 8 9]]
类型:[2][2]string;     数组长度:2;    数据:[[a b] [c d]]
11: 值:1;  12: 值:2;  13: 值:3;
21: 值:4;  22: 值:5;  23: 值:6;
31: 值:7;  32: 值:8;  33: 值:9;
11: 值:a;  12: 值:b;
21: 值:c;  22: 值:d;

2. 切片(Slice)

切片:基于数组实现的一层封装,可变长度的序列,可自动扩容切片为引用类型

2.1 切片声明、初始化

var 变量名 = []<数据类型>
// 声明 + 初始化
var 变量名 = []<数据类型>{}
变量名:= []<数据类型>{}

示例:

// 切片的定义
var arr1 []int
// len获取数据长度
fmt.Printf("类型:%T; \t切片长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
/* 切片初始化 */
// 1. 方式一 var 变量名 = []<数据类型>{}
var arr2 = []float64{1, 2, 4.6}
fmt.Printf("方式一: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr2, len(arr2), arr2)
// 2. 方式二 变量名:= []<数据类型>{}
arr3 := []string{"java", "Golang", "Python"}
fmt.Printf("方式二: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr3, len(arr3), arr3)
// 3. 方式三 var 变量名 = []<数据类型>{} 或 变量名:= []<数据类型>{}
arr4 := []int{2, 4, 6, 7, 8}
fmt.Printf("方式三: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr4, len(arr4), arr4)
// 4. 方式四 指定下标索引初始化索引
arr5 := []float64{0: 2, 2: 3.5, 5: 4.6, 7: 9}
fmt.Printf("方式四: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr5, len(arr5), arr5)
// 5. 切片的循环和数组一致,这里不例举

结果:

类型:[]int;    切片长度:0;    数据:[]
方式一: 类型:[]float64;        切片长度:3;    数据:[1 2 4.6]
方式二: 类型:[]string;         切片长度:3;    数据:[java Golang Python] 
方式三: 类型:[]int;    切片长度:5;    数据:[2 4 6 7 8]
方式四: 类型:[]float64;        切片长度:8;    数据:[2 0 3.5 0 0 4.6 0 9]

2.2 基于数组创建切片

示例:

// 基于数组定义切片
var arr1 = [5]int{10, 29, 49, 58, 32}
fmt.Printf("类型:%T; \t长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
// 1. 切片获取,arr1[:]获取arr1中所有的数据
s1 := arr1[:]
// 切片数据类型为[]int,数组数据类型为[5]int
fmt.Printf("获取所有数据--类型:%T; \t长度:%v; \t数据:%v\n", s1, len(s1), s1)
// 2. 切片获取,arr1[2:]获取arr1中从下标为2开始之后所有的数据【包含下标2】
s2 := arr1[2:]
fmt.Printf("获取下标为2开始之后所有的数据--类型:%T; \t长度:%v; \t数据:%v\n", s1, len(s2), s2)
// 3. 切片获取,arr1[:2]获取arr1中从下标为2之前所有的数据【不包含下标2】
s3 := arr1[:2]
fmt.Printf("获取下标为2之前所有的数据--类型:%T; \t长度:%v; \t数据:%v\n", s3, len(s3), s3)

结果:

类型:[5]int;   长度:5;        数据:[10 29 49 58 32]
获取所有数据--类型:[]int;      长度:5;        数据:[10 29 49 58 32]
获取下标为2开始之后所有的数据--类型:[]int;     长度:3;        数据:[49 58 32]
获取下标为2之前所有的数据--类型:[]int;         长度:2;        数据:[10 29] 

总结:数据的拆分:arr[start:end] 中,含义为:获取arr对应下标区间[start,end)的值,start,end可省略,表示其前或后的所有值。

2.2 切片的长度(len)和容量(cap)*

切片拥有自己的长度和容量:
长度:切片的长度是切片所包含的元素个数。用**len()函数获取
容量:切片的容量从他第一个元素开始,到底层数组元素末尾的个数。用
cap()**函数获取

a := []int{2, 3, 4, 5, 6, 7}
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", a, len(a), cap(a), a)
b := a[3:]
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", b, len(b), cap(b), b)
c := a[:3]
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", c, len(c), cap(c), c)

结果:

类型:[]int, 长度:6, 容量:6, 数据:[2 3 4 5 6 7]
类型:[]int, 长度:3, 容量:3, 数据:[5 6 7]
类型:[]int, 长度:3, 容量:6, 数据:[2 3 4]

在这里插入图片描述

3. nil值

nil是一个预先声明的标识符,表示指针、通道、函数、接口、集合或切片类型的零值。

数据类型声明默认值
bool
int,float0
string""
指针(pointers)nil
数组(array)基本类型默认值的数组
切片(slices)nil
集合(maps)nil
通道(channels)nil
函数(function)nil
// 数组默认值
var arr [3]int
fmt.Println(arr)
// 切片默认值
var slices1 []int
var slices2 = []int{1}
fmt.Println(slices1, slices1 == nil, slices2 == nil)

结果:

[0 0 0]
[] true false

4. 值类型和引用数据类型

值类型: 值类型赋值的两个变量为独立个体,A变化不会引起B的同步更新
引用数据类型:引用数据类型赋值的两个变量为引用同一个变量,A变化会引起B的变化。实际上是因为指向同一片内存空间。典型的示例即:切片
示例:

a1 := [...]int{2, 3, 4, 5}           // 数组 值复制
a2 := []int{2, 3, 4, 5}              // 切片 引用赋值
b1 := a1                             // 赋值给b1
b2 := a2                             // 赋值给b2
b1[0] = 6                            // 同样修改第一个元素值为6
b2[0] = 6                            // 同样修改第一个元素值为6
fmt.Printf("a1=%v,b1=%v \n", a1, b1) // 值类型赋值:b1的修改不会影响a1
fmt.Printf("a2=%v,b2=%v \n", a2, b2) // 引用类型赋值:b2的修改影响了a2

结果:

a1=[2 3 4 5],b1=[6 3 4 5] 
a2=[6 3 4 5],b2=[6 3 4 5] 

5. 切片常用函数

5.1 创建切片:make

make创建切片,make([]int, 10, 11) 分配一个底层数组大小为10,返回长度为11、容量为10的切片int类型切片

var slice1 = make([]int, 10, 11)
slice1[2] = 6
slice1[9] = 20
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice1, len(slice1), cap(slice1), slice1)
/* 	结果:
类型:[]int, 长度:10, 容量:11, 数据:[0 0 6 0 0 0 0 0 0 20]
*/

5.2 扩容切片:append

切片扩容: append(slice, elem1, elem2)或者append(slice, anotherSlice...),slice表示需要扩容的切片,elem*表示添加的元素,anotherSlice表示其他切片

// 切片的扩容不能通过slice[2]下标越界方式,会报错下标越界:index out of range [2] with length 0
var slice2 = make([]int, 0, 0)
// 切片中追加一个元素,并返回最终元素
slice2 = append(slice2, 12, 14, 24)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice2), cap(slice2), slice2)
slice3 := []int{3, 4, 5}
// 切片的合并,slice3...代表slice3中所有的元素列举
var slice4 = append(slice2, slice3...)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice4), cap(slice4), slice4)
/* 结果:
类型:[]int, 长度:3, 容量:3, 数据:[12 14 24]
类型:[]int, 长度:6, 容量:6, 数据:[12 14 24 3 4 5]
 */

5.3 复制切片【深克隆】:copy

深克隆:指的是克隆前后的对象为两个独立的个体,后续修改变更互不影响
浅克隆:指的是克隆前后的对象为同一个引用类型,后续修改A同样影响B的值
copy(dst, src []Type),dst是destination,表示目的变量,src是source,表示对象源,即将src复制给dst

// 切片的扩容不能通过slice[2]下标越界方式,会报错下标越界:index out of range [2] with length 0
var slice2 = make([]int, 0, 0)
// 切片中追加一个元素,并返回最终元素
slice2 = append(slice2, 12, 14, 24)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice2), cap(slice2), slice2)
slice3 := []int{3, 4, 5}
// 切片的合并,slice3...代表slice3中所有的元素列举
var slice4 = append(slice2, slice3...)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice4), cap(slice4), slice4)
// 切片的复制深克隆
slice4Copy := make([]int, len(slice4))
copy(slice4Copy, slice4)
slice4Copy[0] = 6666
fmt.Println(slice4, slice4Copy)
/* 结果:
类型:[]int, 长度:3, 容量:3, 数据:[12 14 24]
类型:[]int, 长度:6, 容量:6, 数据:[12 14 24 3 4 5]
[12 14 24 3 4 5] [6666 14 24 3 4 5]
 */

5.4 切片的删除

Go语言中没有内置删除切片方法,可以使用append方法,与切片再切片结合实现

// 切片的删除
s1 := []int{1, 2, 3, 4, 5, 6}
// 删除元素的索引下标
delIndx := 3
// 通过切片append方法,与切片再切片结合实现,即截取[0,3)和[4,5]的切片数据再合并达到删除效果
s1 = append(s1[:delIndx], s1[delIndx+1:]...)
fmt.Println(s1)
/* 结果:
[1 2 3 5 6]
 */

5.5 sort排序

5.5.1 升序排序

使用sort.Ints、sort.Float64s、sort.Strings进行排序

intList := []int{3, 4, 32, 32, 423, 12}
float64List := []float64{3.13, 4.2, 5.3, 1.1}
stringList := []string{"D", "S", "A", "C"}
// 升序排序
sort.Ints(intList)
sort.Float64s(float64List)
sort.Strings(stringList)
fmt.Println(intList)
fmt.Println(float64List)
fmt.Println(stringList)
/* 结果:
[3 4 12 32 32 423]
[1.1 3.13 4.2 5.3]
[A C D S]
 */

5.5.2 降序排序

结合sort.XXXSlice、sort.Reverse和sort.Sort实现

intList := []int{3, 4, 32, 32, 423, 12}
float64List := []float64{3.13, 4.2, 5.3, 1.1}
stringList := []string{"D", "S", "A", "C"}
/*
	降序排序
		1. sort.IntSlice(intList)表示对intList转成interface,简单理解为将切片转为排序器接口,返回结果类型:data sort.Interface
		2. sort.Reverse(data sort.Interface)表示翻转切片,返回结果类型:data sort.Interface
		3. sort.Sort(data sort.Interface) 表示将结果排序返回数据
	默认当做固定写法:sort.Sort(sort.Reverse(sort.XXXSlice(intList)))
	另外也可以自定义排序算法实现降序排序
*/
sort.Sort(sort.Reverse(sort.IntSlice(intList)))
sort.Sort(sort.Reverse(sort.Float64Slice(float64List)))
sort.Sort(sort.Reverse(sort.StringSlice(stringList)))
fmt.Println(intList)
fmt.Println(float64List)
fmt.Println(stringList)
/* 结果: 
[423 32 32 12 4 3]
[5.3 4.2 3.13 1.1]
[S D C A]
 */

6. 扩展技巧

6.1 语法提示

对一个变量输入“.”符号时,编译器自动提示语法命令,后缀携带!的表示为功能快捷提示,并生成对应的半成品代码

在这里插入图片描述
截图中提示语功能

功能提示语句含义
append!切片追加数据
copy!copy克隆切片
for!fori循环
forr!for range循环
ifnotnil!if not nil 条件判断
last!等价于a[len(a -1)]获取最后一个元素
len!等价于len(a)获取长度
print!打印变量
range!等价于forr!
reverse!翻转切片
sort!自定定排序
var!将a赋值于新的变量

6.2 方法参数、含义使用探究

  1. 鼠标移动至方法名1s以上,显示方法名参数、返回值,含义,描述详情等信息

在这里插入图片描述

  1. 用ctrl按键+鼠标左键,点击方法名,即可进入方法名参数、返回值,含义,描述详情等信息,如果不懂英文,可以通过翻译工具认识逐步了解学习
    在这里插入图片描述

上一篇:Golang学习历程【第四篇 运算符&流程控制】
下一篇:Golang学习历程【第六篇 复合数据类型:map】 待续中。。。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ESP32自动下载电路分享

下面是一个ESP32系列或者ESP8266等电路的一个自动下载电路 在ESP32等模块需要烧写程序的时候&#xff0c;需要通过将EN引脚更改为低电平并将IO0引脚设置为低电平来切换到烧写模式。 有时候也会采用先将IO接到一个按键上&#xff0c;按住按键拉低IO0的同时重新上电的方式进入烧写…

【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析

文章目录 前言一、前提条件二、操作步骤2.1 准备云主机实例2.2 安装docker-compose2.3 使用docker-compose安装Superset2.3.1 克隆 Superset 的 GitHub 存储库2.3.2 通过 Docker Compose 启动 Superset 2.4 开通 OB Cloud 云数据库2.5 获取连接串2.6 使用 Superset 连接 OceanB…

联发科MTK6771/MT6771安卓核心板规格参数介绍

MT6771&#xff0c;也被称为Helio P60&#xff0c;是联发科技(MediaTek)推出的一款中央处理器(CPU)芯片&#xff0c;可运行 android9.0 操作系统的 4G AI 安卓智能模块。MT6771芯片采用了12纳米工艺制造&#xff0c;拥有八个ARM Cortex-A73和Cortex-A53核心&#xff0c;主频分别…

修复 ITunes 在 Windows 或 Mac 上不断崩溃的问题 [100% 有效]

对于 iDevice 用户来说&#xff0c;只能通过 iTunes 在 iDevice 和计算机之间传输文件的困境一直是一个紧迫的问题。所有 iPhone 用户可能都知道&#xff0c;iTunes 并不是一款高效的应用程序&#xff0c;有时性能会很差&#xff0c;例如在 iDevices 和计算机之间传输文件时不断…

【AI大模型】深入GPT-2模型细节:揭秘其卓越性能的秘密

目录 &#x1f354; GPT2的架构 &#x1f354; GPT2模型的细节 2.1 模型过程 2.2 GPT2工作细节探究 &#x1f354; 小结 学习目标 掌握GPT2的架构掌握GPT2的训练任务和模型细节 &#x1f354; GPT2的架构 从模型架构上看, GPT2并没有特别新颖的架构, 它和只带有解码器模块…

C语言 - 理解函数栈帧

一&#xff1a;概述 函数栈帧是函数调用过程中为管理和存储函数相关信息&#xff08;如局部变量、返回地址等&#xff09;而在栈上分配的一块内存区域。它是实现函数调用、递归和返回的关键机制。 二&#xff1a;栈帧的组成 一个典型的栈帧通常包含以下内容&#xff08;从高地…

windows终端conda activate命令行不显示环境名

问题&#xff1a; 始终不显示环境名 解决 首先需要配置conda的环境变量 确保conda --version能显示版本 然后对cmd进行初始化&#xff0c;如果用的是vscode中的终端&#xff0c;那需要对powershell进行初始化 Windows CMD conda init cmd.exeWindows PowerShell conda …

检索增强生成 和思维链 结合: 如何创建检索增强思维链 (RAT)?

论文地址&#xff1a;https://arxiv.org/pdf/2403.05313 Github地址&#xff1a;https://github.com/CraftJarvis/RAT 想象一下&#xff0c;一个人工智能助手可以像莎士比亚一样写作&#xff0c;像专家一样推理。这听起来很了不起&#xff0c;对吧&#xff1f;但是&#xff0…

Fabric链码部署测试

参考链接&#xff1a;运行 Fabric 应用程序 — Hyperledger Fabric Docs 主文档 (hyperledger-fabric.readthedocs.io) &#xff08;2&#xff09;fabric2.4.3部署运行自己的链码 - 知乎 (zhihu.com) Fabric2.0测试网络部署链码 - 辉哥哥~ - 博客园 (cnblogs.com) 1.启动测试…

如何单独安装 MATLAB 工具箱

很多时候由于 MATLAB 太大而选择安装一些 Toolbox&#xff0c;但用着用着发现要用到某个没有安装的 Toolbox&#xff0c;这时候就需要再单独安装这个 Toolbox&#xff0c;下面提供两种方法。 本文以安装 系统辨识工具箱 System Identification Toolbox 为例。 方法一&#xf…

Anaconda/Pytorch/PyCharm/Jupyter安装及使用

1.ANACONDA安装 Anaconda 是全球领先的数据科学与机器学习平台&#xff0c;专为开发者、数据分析师设计。通过 Anaconda&#xff0c;您可以轻松管理数据环境、安装依赖包&#xff0c;快速启动数据分析、机器学习项目。 丰富的 Python 数据科学库&#xff1a;Anaconda 集成了常…

RocketMQ消费者如何消费消息以及ack

1.前言 此文章是在儒猿课程中的学习笔记&#xff0c;感兴趣的想看原来的课程可以去咨询儒猿课堂 这篇文章紧挨着上一篇博客来进行编写&#xff0c;有些不清楚的可以看下上一篇博客&#xff1a; https://blog.csdn.net/u013127325/article/details/144934073 2.broker是如何…

【Logstash02】企业级日志分析系统ELK之Logstash 输入 Input 插件

Logstash 使用 Logstash 命令 官方文档 https://www.elastic.co/guide/en/logstash/current/first-event.html #各种插件 https://www.elastic.co/guide/en/logstash/current/input-plugins.html https://www.elastic.co/guide/en/logstash/current/filter-plugins.html htt…

【设计模式】 基本原则、设计模式分类

设计模式 设计模式是软件工程中的一种通用术语&#xff0c;指的是针对特定问题的经过实践验证的解决方案。设计模式并不是最终的代码实现&#xff0c;而是描述了如何解决某一类问题的思路和方法。 如果熟悉了设计模式&#xff0c;当遇到类似的场景&#xff0c;我们可以快速地…

【AI学习】Transformer深入学习(二):从MHA、MQA、GQA到MLA

前面文章&#xff1a; 《Transformer深入学习&#xff08;一&#xff09;&#xff1a;Sinusoidal位置编码的精妙》 一、MHA、MQA、GQA 为了降低KV cache&#xff0c;MQA、GQA作为MHA的变体&#xff0c;很容易理解。 多头注意力&#xff08;MHA&#xff09;&#xff1a; 多头注…

【DevOps】Jenkins部署

Jenkins部署 文章目录 Jenkins部署资源列表基础环境一、部署Gilab1.1、安装Gitlab1.2、修改配置文件1.3、加载配置文件1.4、访问Gitlab1.5、修改root登录密码1.6、创建demo测试项目1.7、上传代码1.8、验证上传的代码 二、部署Jenkins所需软件2.1、部署JDK2.2、部署Tomcat2.3、部…

Node.js - 文件操作

1. 文件写入 文件写入是计算机非常常见的操作&#xff0c;下载文件&#xff0c;安装软件&#xff0c;保存程序日志&#xff0c;视频录制等都使用到了 1.1 异步写入 const fs require("fs");// 写入文件 fs.writeFile(./sentence.txt, "Hello world", e…

数据结构复习 (顺序查找,对半查找,斐波那契查找,插值查找,分块查找)

查找&#xff08;检索&#xff09;&#xff1a; 定义&#xff1a;从给定的数据中找到对应的K 1&#xff0c;顺序查找&#xff1a; O(n)的从前向后的遍历 2&#xff0c;对半查找&#xff0c;要求有序 从中间开始查找&#xff0c;每次检查中间的是否正确&#xff0c;不正确就…

kafka使用以及基于zookeeper集群搭建集群环境

一、环境介绍 zookeeper下载地址&#xff1a;https://zookeeper.apache.org/releases.html kafka下载地址&#xff1a;https://kafka.apache.org/downloads 192.168.142.129 apache-zookeeper-3.8.4-bin.tar.gz kafka_2.13-3.6.0.tgz 192.168.142.130 apache-zookee…

Redis的内存预分配策略

Redis的内存预分配策略是一种优化手段&#xff0c;旨在减少频繁的内存分配和释放操作对性能的影响。以下是对Redis在使用各数据结构类型时内存变化以及触发底层数据结构变化条件的详细分析&#xff1a; 一、内存预分配策略概述 Redis通过预先分配足够的内存&#xff0c;可以提高…